@Test public void testAsynchronousClose() throws IOException, InterruptedException { RegularFile file = regularFile(10); final FileChannel channel = channel(file, READ, WRITE); file.writeLock().lock(); // ensure all operations on the channel will block ExecutorService executor = Executors.newCachedThreadPool(); List<Future<?>> futures = queueAllBlockingOperations(channel, executor); // ensure time for operations to start blocking Uninterruptibles.sleepUninterruptibly(10, MILLISECONDS); channel.close(); for (Future<?> future : futures) { try { future.get(); fail(); } catch (ExecutionException expected) { assertTrue(expected.getCause() instanceof AsynchronousCloseException); } } }
@Test public void testCloseByInterrupt() throws IOException, InterruptedException { RegularFile file = regularFile(10); final FileChannel channel = channel(file, READ, WRITE); file.writeLock().lock(); // ensure all operations on the channel will block ExecutorService executor = Executors.newCachedThreadPool(); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<Throwable> interruptException = new AtomicReference<>(); // This thread, being the first to run, will be blocking on the interruptible lock (the byte // file's write lock) and as such will be interrupted properly... the other threads will be // blocked on the lock that guards the position field and the specification that only one method // on the channel will be in progress at a time. That lock is not interruptible, so we must // interrupt this thread. Thread thread = new Thread( new Runnable() { @Override public void run() { try { channel.write(ByteBuffer.allocate(20)); latch.countDown(); } catch (Throwable e) { interruptException.set(e); latch.countDown(); } } }); thread.start(); // ensure time for thread to start blocking on the write lock Uninterruptibles.sleepUninterruptibly(5, MILLISECONDS); List<Future<?>> futures = queueAllBlockingOperations(channel, executor); // ensure time for operations to start blocking Uninterruptibles.sleepUninterruptibly(10, MILLISECONDS); // interrupting this blocking thread closes the channel and makes all the other threads // throw AsynchronousCloseException... the operation on this thread should throw // ClosedByInterruptException thread.interrupt(); latch.await(); assertTrue(interruptException.get() instanceof ClosedByInterruptException); for (Future<?> future : futures) { try { future.get(); fail(); } catch (ExecutionException expected) { assertTrue(expected.getCause() instanceof AsynchronousCloseException); } } }