/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ * Other contributors include Andrew Wright, Jeffrey Hayes, * Pat Fisher, Mike Judd. */ package jsr166; import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import junit.framework.Test; public class SynchronousQueueTest extends JSR166TestCase { // android-note: These tests have been moved into their own separate // classes to work around CTS issues. // // public static class Fair extends BlockingQueueTest { // protected BlockingQueue emptyCollection() { // return new SynchronousQueue(true); // } // } // public static class NonFair extends BlockingQueueTest { // protected BlockingQueue emptyCollection() { // return new SynchronousQueue(false); // } // } // android-note: Removed because the CTS runner does a bad job of // retrying tests that have suite() declarations. // // public static void main(String[] args) { // main(suite(), args); // } // public static Test suite() { // return newTestSuite(SynchronousQueueTest.class, // new Fair().testSuite(), // new NonFair().testSuite()); // } /** * Any SynchronousQueue is both empty and full */ public void testEmptyFull() { testEmptyFull(false); } public void testEmptyFull_fair() { testEmptyFull(true); } public void testEmptyFull(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); assertTrue(q.isEmpty()); assertEquals(0, q.size()); assertEquals(0, q.remainingCapacity()); assertFalse(q.offer(zero)); } /** * offer fails if no active taker */ public void testOffer() { testOffer(false); } public void testOffer_fair() { testOffer(true); } public void testOffer(boolean fair) { SynchronousQueue q = new SynchronousQueue(fair); assertFalse(q.offer(one)); } /** * add throws IllegalStateException if no active taker */ public void testAdd() { testAdd(false); } public void testAdd_fair() { testAdd(true); } public void testAdd(boolean fair) { SynchronousQueue q = new SynchronousQueue(fair); assertEquals(0, q.remainingCapacity()); try { q.add(one); shouldThrow(); } catch (IllegalStateException success) {} } /** * addAll(this) throws IllegalArgumentException */ public void testAddAll_self() { testAddAll_self(false); } public void testAddAll_self_fair() { testAddAll_self(true); } public void testAddAll_self(boolean fair) { SynchronousQueue q = new SynchronousQueue(fair); try { q.addAll(q); shouldThrow(); } catch (IllegalArgumentException success) {} } /** * addAll throws ISE if no active taker */ public void testAddAll_ISE() { testAddAll_ISE(false); } public void testAddAll_ISE_fair() { testAddAll_ISE(true); } public void testAddAll_ISE(boolean fair) { SynchronousQueue q = new SynchronousQueue(fair); Integer[] ints = new Integer[1]; for (int i = 0; i < ints.length; i++) ints[i] = i; Collection<Integer> coll = Arrays.asList(ints); try { q.addAll(coll); shouldThrow(); } catch (IllegalStateException success) {} } /** * put blocks interruptibly if no active taker */ public void testBlockingPut() { testBlockingPut(false); } public void testBlockingPut_fair() { testBlockingPut(true); } public void testBlockingPut(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); final CountDownLatch pleaseInterrupt = new CountDownLatch(1); Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { Thread.currentThread().interrupt(); try { q.put(99); shouldThrow(); } catch (InterruptedException success) {} assertFalse(Thread.interrupted()); pleaseInterrupt.countDown(); try { q.put(99); shouldThrow(); } catch (InterruptedException success) {} assertFalse(Thread.interrupted()); }}); await(pleaseInterrupt); assertThreadStaysAlive(t); t.interrupt(); awaitTermination(t); assertEquals(0, q.remainingCapacity()); } /** * put blocks interruptibly waiting for take */ public void testPutWithTake() { testPutWithTake(false); } public void testPutWithTake_fair() { testPutWithTake(true); } public void testPutWithTake(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); final CountDownLatch pleaseTake = new CountDownLatch(1); final CountDownLatch pleaseInterrupt = new CountDownLatch(1); Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { pleaseTake.countDown(); q.put(one); pleaseInterrupt.countDown(); try { q.put(99); shouldThrow(); } catch (InterruptedException success) {} assertFalse(Thread.interrupted()); }}); await(pleaseTake); assertEquals(0, q.remainingCapacity()); try { assertSame(one, q.take()); } catch (InterruptedException e) { threadUnexpectedException(e); } await(pleaseInterrupt); assertThreadStaysAlive(t); t.interrupt(); awaitTermination(t); assertEquals(0, q.remainingCapacity()); } /** * timed offer times out if elements not taken */ public void testTimedOffer() { testTimedOffer(false); } public void testTimedOffer_fair() { testTimedOffer(true); } public void testTimedOffer(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); final CountDownLatch pleaseInterrupt = new CountDownLatch(1); Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { long startTime = System.nanoTime(); assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS)); assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); pleaseInterrupt.countDown(); try { q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); shouldThrow(); } catch (InterruptedException success) {} }}); await(pleaseInterrupt); assertThreadStaysAlive(t); t.interrupt(); awaitTermination(t); } /** * poll return null if no active putter */ public void testPoll() { testPoll(false); } public void testPoll_fair() { testPoll(true); } public void testPoll(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); assertNull(q.poll()); } /** * timed poll with zero timeout times out if no active putter */ public void testTimedPoll0() { testTimedPoll0(false); } public void testTimedPoll0_fair() { testTimedPoll0(true); } public void testTimedPoll0(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); try { assertNull(q.poll(0, MILLISECONDS)); } catch (InterruptedException e) { threadUnexpectedException(e); } } /** * timed poll with nonzero timeout times out if no active putter */ public void testTimedPoll() { testTimedPoll(false); } public void testTimedPoll_fair() { testTimedPoll(true); } public void testTimedPoll(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); long startTime = System.nanoTime(); try { assertNull(q.poll(timeoutMillis(), MILLISECONDS)); } catch (InterruptedException e) { threadUnexpectedException(e); } assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); } /** * timed poll before a delayed offer times out, returning null; * after offer succeeds; on interruption throws */ public void testTimedPollWithOffer() { testTimedPollWithOffer(false); } public void testTimedPollWithOffer_fair() { testTimedPollWithOffer(true); } public void testTimedPollWithOffer(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); final CountDownLatch pleaseOffer = new CountDownLatch(1); final CountDownLatch pleaseInterrupt = new CountDownLatch(1); Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { long startTime = System.nanoTime(); assertNull(q.poll(timeoutMillis(), MILLISECONDS)); assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); pleaseOffer.countDown(); startTime = System.nanoTime(); assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); Thread.currentThread().interrupt(); try { q.poll(LONG_DELAY_MS, MILLISECONDS); shouldThrow(); } catch (InterruptedException success) {} assertFalse(Thread.interrupted()); pleaseInterrupt.countDown(); try { q.poll(LONG_DELAY_MS, MILLISECONDS); shouldThrow(); } catch (InterruptedException success) {} assertFalse(Thread.interrupted()); assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); }}); await(pleaseOffer); long startTime = System.nanoTime(); try { assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS)); } catch (InterruptedException e) { threadUnexpectedException(e); } assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); await(pleaseInterrupt); assertThreadStaysAlive(t); t.interrupt(); awaitTermination(t); } /** * peek() returns null if no active putter */ public void testPeek() { testPeek(false); } public void testPeek_fair() { testPeek(true); } public void testPeek(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); assertNull(q.peek()); } /** * element() throws NoSuchElementException if no active putter */ public void testElement() { testElement(false); } public void testElement_fair() { testElement(true); } public void testElement(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); try { q.element(); shouldThrow(); } catch (NoSuchElementException success) {} } /** * remove() throws NoSuchElementException if no active putter */ public void testRemove() { testRemove(false); } public void testRemove_fair() { testRemove(true); } public void testRemove(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); try { q.remove(); shouldThrow(); } catch (NoSuchElementException success) {} } /** * contains returns false */ public void testContains() { testContains(false); } public void testContains_fair() { testContains(true); } public void testContains(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); assertFalse(q.contains(zero)); } /** * clear ensures isEmpty */ public void testClear() { testClear(false); } public void testClear_fair() { testClear(true); } public void testClear(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); q.clear(); assertTrue(q.isEmpty()); } /** * containsAll returns false unless empty */ public void testContainsAll() { testContainsAll(false); } public void testContainsAll_fair() { testContainsAll(true); } public void testContainsAll(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); Integer[] empty = new Integer[0]; assertTrue(q.containsAll(Arrays.asList(empty))); Integer[] ints = new Integer[1]; ints[0] = zero; assertFalse(q.containsAll(Arrays.asList(ints))); } /** * retainAll returns false */ public void testRetainAll() { testRetainAll(false); } public void testRetainAll_fair() { testRetainAll(true); } public void testRetainAll(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); Integer[] empty = new Integer[0]; assertFalse(q.retainAll(Arrays.asList(empty))); Integer[] ints = new Integer[1]; ints[0] = zero; assertFalse(q.retainAll(Arrays.asList(ints))); } /** * removeAll returns false */ public void testRemoveAll() { testRemoveAll(false); } public void testRemoveAll_fair() { testRemoveAll(true); } public void testRemoveAll(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); Integer[] empty = new Integer[0]; assertFalse(q.removeAll(Arrays.asList(empty))); Integer[] ints = new Integer[1]; ints[0] = zero; assertFalse(q.containsAll(Arrays.asList(ints))); } /** * toArray is empty */ public void testToArray() { testToArray(false); } public void testToArray_fair() { testToArray(true); } public void testToArray(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); Object[] o = q.toArray(); assertEquals(0, o.length); } /** * toArray(Integer array) returns its argument with the first * element (if present) nulled out */ public void testToArray2() { testToArray2(false); } public void testToArray2_fair() { testToArray2(true); } public void testToArray2(boolean fair) { final SynchronousQueue<Integer> q = new SynchronousQueue<Integer>(fair); Integer[] a; a = new Integer[0]; assertSame(a, q.toArray(a)); a = new Integer[3]; Arrays.fill(a, 42); assertSame(a, q.toArray(a)); assertNull(a[0]); for (int i = 1; i < a.length; i++) assertEquals(42, (int) a[i]); } /** * toArray(null) throws NPE */ public void testToArray_null() { testToArray_null(false); } public void testToArray_null_fair() { testToArray_null(true); } public void testToArray_null(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); try { Object[] o = q.toArray(null); shouldThrow(); } catch (NullPointerException success) {} } /** * iterator does not traverse any elements */ public void testIterator() { testIterator(false); } public void testIterator_fair() { testIterator(true); } public void testIterator(boolean fair) { assertIteratorExhausted(new SynchronousQueue(fair).iterator()); } /** * iterator remove throws ISE */ public void testIteratorRemove() { testIteratorRemove(false); } public void testIteratorRemove_fair() { testIteratorRemove(true); } public void testIteratorRemove(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); Iterator it = q.iterator(); try { it.remove(); shouldThrow(); } catch (IllegalStateException success) {} } /** * toString returns a non-null string */ public void testToString() { testToString(false); } public void testToString_fair() { testToString(true); } public void testToString(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); String s = q.toString(); assertNotNull(s); } /** * offer transfers elements across Executor tasks */ public void testOfferInExecutor() { testOfferInExecutor(false); } public void testOfferInExecutor_fair() { testOfferInExecutor(true); } public void testOfferInExecutor(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); final CheckedBarrier threadsStarted = new CheckedBarrier(2); final ExecutorService executor = Executors.newFixedThreadPool(2); try (PoolCleaner cleaner = cleaner(executor)) { executor.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { assertFalse(q.offer(one)); threadsStarted.await(); assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS)); assertEquals(0, q.remainingCapacity()); }}); executor.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { threadsStarted.await(); assertSame(one, q.take()); }}); } } /** * timed poll retrieves elements across Executor threads */ public void testPollInExecutor() { testPollInExecutor(false); } public void testPollInExecutor_fair() { testPollInExecutor(true); } public void testPollInExecutor(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); final CheckedBarrier threadsStarted = new CheckedBarrier(2); final ExecutorService executor = Executors.newFixedThreadPool(2); try (PoolCleaner cleaner = cleaner(executor)) { executor.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { assertNull(q.poll()); threadsStarted.await(); assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); assertTrue(q.isEmpty()); }}); executor.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { threadsStarted.await(); q.put(one); }}); } } /** * a deserialized serialized queue is usable */ public void testSerialization() { final SynchronousQueue x = new SynchronousQueue(); final SynchronousQueue y = new SynchronousQueue(false); final SynchronousQueue z = new SynchronousQueue(true); assertSerialEquals(x, y); assertNotSerialEquals(x, z); SynchronousQueue[] qs = { x, y, z }; for (SynchronousQueue q : qs) { SynchronousQueue clone = serialClone(q); assertNotSame(q, clone); assertSerialEquals(q, clone); assertTrue(clone.isEmpty()); assertEquals(0, clone.size()); assertEquals(0, clone.remainingCapacity()); assertFalse(clone.offer(zero)); } } /** * drainTo(c) of empty queue doesn't transfer elements */ public void testDrainTo() { testDrainTo(false); } public void testDrainTo_fair() { testDrainTo(true); } public void testDrainTo(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); ArrayList l = new ArrayList(); q.drainTo(l); assertEquals(0, q.size()); assertEquals(0, l.size()); } /** * drainTo empties queue, unblocking a waiting put. */ public void testDrainToWithActivePut() { testDrainToWithActivePut(false); } public void testDrainToWithActivePut_fair() { testDrainToWithActivePut(true); } public void testDrainToWithActivePut(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { q.put(one); }}); ArrayList l = new ArrayList(); long startTime = System.nanoTime(); while (l.isEmpty()) { q.drainTo(l); if (millisElapsedSince(startTime) > LONG_DELAY_MS) fail("timed out"); Thread.yield(); } assertTrue(l.size() == 1); assertSame(one, l.get(0)); awaitTermination(t); } /** * drainTo(c, n) empties up to n elements of queue into c */ public void testDrainToN() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); Thread t1 = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { q.put(one); }}); Thread t2 = newStartedThread(new CheckedRunnable() { public void realRun() throws InterruptedException { q.put(two); }}); ArrayList l = new ArrayList(); int drained; while ((drained = q.drainTo(l, 1)) == 0) Thread.yield(); assertEquals(1, drained); assertEquals(1, l.size()); while ((drained = q.drainTo(l, 1)) == 0) Thread.yield(); assertEquals(1, drained); assertEquals(2, l.size()); assertTrue(l.contains(one)); assertTrue(l.contains(two)); awaitTermination(t1); awaitTermination(t2); } /** * remove(null), contains(null) always return false */ public void testNeverContainsNull() { Collection<?> q = new SynchronousQueue(); assertFalse(q.contains(null)); assertFalse(q.remove(null)); } }