@Test
    public void testAddAndRemove() throws Exception {

        final int runTimes = 100;
        final int threadCount = 50;

        for (int r=0;r<runTimes;r++) {

            System.out.println("RUN TIME:" + r);

            final CyclicBarrier barrier = new CyclicBarrier(threadCount*2);
            final CountDownLatch latch = new CountDownLatch(threadCount*2);

            final AtomicInteger appendCount = new AtomicInteger();
            final AtomicInteger appendStarted = new AtomicInteger();
            final AtomicInteger removeStarted = new AtomicInteger();
            final AtomicInteger removeCount = new AtomicInteger();
            final TestConcurrentQueue<Integer> queue = new TestConcurrentQueue<Integer>();

            for (int i=0;i<threadCount;i++) {
                new Thread(new Runnable() {
                    public void run() {
                        waitBarrier(barrier);
                        removeStarted.incrementAndGet();
                        for (;;) {
                            final SimpleIterator<Integer> iter = queue.iterator();
                            if (iter.next() != null && iter.remove()) {
                                break;
                            }
                            Thread.yield(); // Note that 'yield'. Without this thread will eat resources without giving other threads to proceed
                            // (which may be an appending thread)
                        }
                        removeCount.incrementAndGet();
                        latch.countDown();
                    }
                }).start();
            }
            for (int i=0;i<threadCount;i++) {
                new Thread(new Runnable() {
                    public void run() {
                        waitBarrier(barrier);
                        appendStarted.incrementAndGet();
                        queue.add(100);
                        appendCount.incrementAndGet();
                        latch.countDown();
                    }
                }).start();
            }
            latch.await(10, TimeUnit.SECONDS);

            System.out.println("Append started: " + appendStarted + "; Remove started: " + removeStarted +
                    "; Append finished: " + appendCount + "; Remove finished: " + removeCount);

            assertThat(appendStarted.get()).as("appendStarted").isEqualTo(threadCount);
            assertThat(removeStarted.get()).as("removeStarted").isEqualTo(threadCount);
            assertThat(appendCount.get()).as("appendCount").isEqualTo(threadCount);
            assertThat(removeCount.get()).as("removeCount").isEqualTo(threadCount);
            assertThat(queue.isEmpty()).isTrue();
        }
    }