In the following example, the main thread submitted a runnable to ExecutorService to run it in a worker thread.
The runnable's run method has a while loop. In each round, it checks a boolean flag then adds a new member to a BlockingQueue.
One second later, main calls cancel() method to set the flag, hoping the working thread will detect it in order to exit the while loop. However, the worker thread is blocking on the filled BlockingQueue and never emerges to check the flag. As a result, the hanging worker thread prevent the program to exit.
CHAP7>cat BrokenPrimeproducer.java
import java.math.BigInteger;
import java.util.concurrent.*;
/**
* BrokenPrimeProducer
* <p/>
* Unreliable cancellation that can leave producers stuck in a blocking operation
*/
class BrokenPrimeProducer extends Thread {
private static ExecutorService exec = Executors.newCachedThreadPool();
private final BlockingQueue<BigInteger> queue;
private volatile boolean cancelled = false;
BrokenPrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!cancelled)
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
}
}
public void cancel() {
cancelled = true;
}
public static void main(String args[]) {
BrokenPrimeProducer bpp = new BrokenPrimeProducer(new LinkedBlockingQueue<BigInteger>(5));
System.out.println(bpp.queue.size());
exec.submit(bpp);
try {
Thread.sleep(1000);
bpp.cancel();
System.out.println(bpp.queue.size());
exec.shutdown();
exec.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CHAP7>javac BrokenPrimeproducer.java
CHAP7>java BrokenPrimeproducer
Error: Could not find or load main class BrokenPrimeproducer
CHAP7>java BrokenPrimeProducer
0
5
^CCHAP7>