Repository: netty/netty
File: buffer/src/test/java/io/netty/buffer/AbstractByteBufTest.java (Java)

Code before:
        }

        int iterations = 256;
        Semaphore start = new Semaphore(0);
        Semaphore finish = new Semaphore(0);
        char[] cs = new char[(int) (bufSize / charset.newEncoder().maxBytesPerChar())];
        Arrays.fill(cs, 'a');
        final CharSequence str = charSeqType.create(cs);
        ExecutorService executor = Executors.newFixedThreadPool(bufs.length);
        try {
            Future<Void>[] futures = new Future[bufs.length];
            for (int i = 0; i < bufs.length; i++) {
                final ByteBuf buf = bufs[i];
                futures[i] = executor.submit(() -> {
                    finish.release();
                    start.acquire();
                    for (int j = 0; j < iterations; j++) {
                        buf.setCharSequence(0, str, charset);
                    }
                    return null;
                });
            }
            finish.acquire(bufs.length);
            start.release(bufs.length);
            for (Future<Void> future : futures) {
                future.get();
            }
            for (ByteBuf buf : bufs) {
                buf.release();
            }
        } finally {
            executor.shutdown();
        }
    }

    @Test
    public void readByteThrowsIndexOutOfBoundsException() {
        final ByteBuf buffer = newBuffer(8);
        try {
            assertThrows(IndexOutOfBoundsException.class, new Executable() {
                @Override
                public void execute() {
                    buffer.writeByte(0);
                    assertEquals((byte) 0, buffer.readByte());
                    buffer.readByte();
                }
            });
        } finally {
            buffer.release();
        }
    }

Review comment (bug):
Shouldn't we await first on all and then check if any of them is failed ? Otherwise we might have stuff still running while shutdown the executor 

Code after:
        for (int i = 0; i < bufs.length; i++) {
            bufs[i] = newBuffer(bufSize);
        }

        int iterations = 256;
        Semaphore start = new Semaphore(0);
        Semaphore finish = new Semaphore(0);
        char[] cs = new char[(int) (bufSize / charset.newEncoder().maxBytesPerChar())];
        Arrays.fill(cs, 'a');
        final CharSequence str = charSeqType.create(cs);
        ExecutorService executor = Executors.newFixedThreadPool(bufs.length);
        try {
            Future<Void>[] futures = new Future[bufs.length];
            for (int i = 0; i < bufs.length; i++) {
                final ByteBuf buf = bufs[i];
                futures[i] = executor.submit(() -> {
                    finish.release();
                    start.acquire();
                    for (int j = 0; j < iterations; j++) {
                        buf.setCharSequence(0, str, charset);
                    }
                    return null;
                });
            }
            finish.acquire(bufs.length);
            start.release(bufs.length);
            Exception e = null;
            for (Future<Void> future : futures) {
                try {
                    future.get();
                } catch (InterruptedException ex) {
                    if (e != null) {
                        ex.addSuppressed(e);
                    }
                    throw ex; // Propagate interrupted exceptions immediately.
                } catch (ExecutionException ex) {
                    if (e != null) {
                        e = ex;
                    } else {
                        e.addSuppressed(ex);
                    }
                }
            }
            if (e != null) {
                fail("Worker threads failed", e);
            }
        } finally {
            executor.shutdown();
            for (ByteBuf buf : bufs) {
                buf.release();
            }