The 7th chapter of "Java Concurrency Programming" is the cancellation and closure of tasks. I think this chapter and the 6th chapter of the task of the same importance, a good software and barely run software between the most important difference is that good-performing software can very well deal with the failure, shutdown and cancellation process.
I. CANCELLATION of MISSION
There is no secure preemption in Java (the immediate stop of an interrupt request) to stop the thread, and there is no secure preemptive method to stop the task. There are only a few collaborative mechanisms, such as setting an identity where the request has been canceled. In the following example, Primegenarator continues to list primes until it is canceled. The Cancel method sets the cancelled identity, and the main loop checks the identity before searching for the next prime number, and for this process to work reliably, the cancelled must be of type volatile.
//use a volatile type of domain to protect the cancellation state Public classPrimegeneratorImplementsrunnable{Private FinalList<biginteger> primes =NewArraylist<biginteger>(); Private volatile Booleancancelled; @Override Public voidrun () {BigInteger P=Biginteger.one; while(!cancelled) {P=P.nextprobableprime (); synchronized( This) {Primes.add (P); } } } Public voidCancel () {cancelled =true;} Public synchronizedList<biginteger>get () {return NewArraylist<biginteger>(primes); }}
Test, let Genarator only perform one second.
Public Static void throws exception{ new primegenerator (); New Thread (Generator). Start (); Try { Thread.Sleep (+); } finally { generator.cancel (); } System.out.println (Generator.get ());;}
Printing results are not displayed, but just a few primes.
Second, interruption
Each thread has a Boolean type of interrupt state. The interrupt state of this thread will be set to True when thread is disconnected, and in thread it contains a method for interrupting threads and querying the interrupt state of the thread as follows:
public class thread{ // Interrupts the target thread (but the thread does not stop immediately, that is, no preemptive stop) public void interrupt () {} // The interrupt state of the returned thread has been interrupted: true is not interrupted: false public boolean isinterrupted () {} // Clears the interrupt state of the current thread and returns the value before it, which is the only way to clear the interrupt state Public static boolean interrupted () {}}
If a thread is interrupted, there are two things that happen:1. Clears the interrupt state 2. Throws a Interruptedexception exception , so sometimes if there is another operation after capturing Interruptedexception, To break the current thread: Thread.CurrentThread (). interrupt (); and then do other things.
It is also important to note that calling interrupt does not immediately stop the work being done by the target thread, but simply passes the message that the request was interrupted. The correct understanding of an interrupt operation is that it does not actually interrupt a running thread, but simply makes an interrupt request, which is then interrupted by the thread at the next appropriate moment.
Now we look back at the example of Primegenarator, if there is a blocking queue in the code, then this cancellation with volatile flags can be problematic, such as prime generation based on producer and consumer patterns:
//producersclassBrokenprimeproducerextendsthread{Private FinalBlockingqueue<biginteger>queue; Private volatile BooleanCancelled =false; PublicBrokenprimeproducer (blockingqueue<biginteger>queue) { This. Queue =queue; } @Override Public voidrun () {Try{BigInteger P=Biginteger.one; while(!cancelled) {Queue.put (P=p.nextprobableprime ()); } } Catch(Interruptedexception e) {}} Public voidCancel () {cancelled =true;}}
The consumer's code is not written, nothing more than to remove the prime number from the blocking queue. You see, at this point, the producer threads generate prime numbers and put them in a blocking queue, and if the producer is faster than the consumer's processing speed, the queue will be filled up, the put method will be blocked, and if the consumer wants to cancel the producer this task is useless, because the producer is blocked in the Put method. This problem is well resolved, using interrupts to replace the Boolean identity. To modify the producer code:
classPrimeproducerextendsthread{Private FinalBlockingqueue<biginteger>queue; Primeproducer (Blockingqueue<BigInteger>queue) { This. Queue =queue; } @Override Public voidrun () {Try{BigInteger P=Biginteger.one; //The condition changes to whether the current thread is interrupted while(!Thread.CurrentThread (). isinterrupted ()) {Queue.put (P=p.nextprobableprime ()); } } Catch(interruptedexception e) {/*allow thread to exit*/ } } Public voidCancel () {interrupt ();}}
If the consumer no longer needs the producer, it can directly interrupt the producer thread, so that even if the producer is in a blocked state, it can exit. Thus, interruption is the most reasonable way to achieve cancellation .
Java Concurrency Foundation (iv)---cancellation and shutdown