The definition of a thread gives us a way to execute multiple tasks concurrently, and in most cases we let each task execute itself to the end, which guarantees the consistency of the transaction, but sometimes we want to cancel the task in the execution of the task and cause the thread to stop. In Java it is not easy for threads to stop safely, quickly and reliably, nor does Java provide any reliable means to terminate the execution of threads. Back in the sixth section, there are two concepts of preemption and collaboration in the thread scheduling strategy, similar to which the interrupt mechanism has a cooperative and preemptive type.
Historically, Java used the Stop () method to terminate the running of threads, which were preemptive interrupts. But it has caused a lot of problems and is already deprecated by the JDK. Calling the Stop () method means that ① will release all locks held by the thread, and the release of the lock is not controllable. ② will immediately throw an Threaddeath exception, no matter where the program runs, but it is not always valid, if there is a lock contention for the terminated thread; The 1th will lead to data consistency issues, which is well understood, general data locking is to protect the consistency of the data, and the thread stops with the release of the lock held, It is likely to result in inconsistent data being protected, resulting in errors in program operations. The 2nd is more ambiguous, it is to illustrate the problem is that there may be some situation the stop () method can not terminate the thread in time, and may not even terminate the thread. Look at the following code to see what happens, it seems that the thread MT because the Stop () method will stop, even if the Execut method is a dead loop, as long as the Stop () method thread will end, the infinite loop will also end. In fact, because we used the synchronized adornment in the Execute method, the synchronous method means that the Mt object will be locked when execute executes, and the Stop () method of thread is synchronous, so the Stop () of the MT thread is called. The Mt object lock must be acquired before the method, but the Mt object lock is occupied by the Execute method and is not freed, so the Stop () method never gets the Mt object lock, and finally concludes that using the Stop () method to stop the thread is unreliable, it may not always be able to effectively terminate the thread.
public class Threadstop {
public static Voidmain (string[] args) {
Thread mt= new MyThread ();
Mt.start ();
try {
Thread.CurrentThread (). Sleep (100);
} catch (Interruptedexception e) {
E.printstacktrace ();
}
Mt.stop ();
}
Static Classmythread extends Thread {
Publicvoid Run () {
Execute ();
}
privatesynchronized void execute () {
while (true) {
}
}
}
}
After a long period of development, Java finally chose to use a collaborative interrupt mechanism to implement interrupts. The principle of collaborative interrupts is simple, the core is to first mark the interrupt identity, a thread set a thread's interrupt identity bit, the thread marked the break bit at the appropriate time node will throw an exception, catch the exception to do the corresponding processing. There are three main points to consider when implementing a collaboration outage: ① is the implementation of polling interrupt identification at the Java level or in the JVM, and the granularity of the ② poll is minimized so as to ensure the timeliness of response; the choice of the time node of the ③ polling is actually the method of polling, For example, the JVM implements a polling operation that interrupts the identification of the thread class's Wait (), sleep (), and join () methods.
Where is the interrupt ID placed? Interrupts are for thread instances, and from the Java level, it is certainly appropriate to place the identity variable in the thread, but because it is maintained by the JVM, the interrupt identity is maintained by the local method. At the Java level, only a few APIs are left to operate the interrupt ID, as below,
public class thread{
Public Voidinterrupt () {...}
Public booleanisinterrupted () {...}
public static booleaninterrupted () {...}
}
The above three methods are used to set the thread as the interrupt state, determine if the thread state is interrupted, clear the current thread break state, and return the value before it. The interrupt ID is set by the interrupt () method, and if the non-blocking thread simply changes the interrupt state, the thread will continue to run down, but if it is in a unblocking thread, such as the execution of sleep (), wait (), join () The thread that waits for the method throws the interruptedexception exception because the interrupt state is set, and the program handles this exception capture.
The three main points mentioned above, the first is the implementation of polling at which level, there is no special requirement, in practice, as long as there is no logical problem, at the Java level or the JVM level of implementation is possible, such as common thread sleep, wait, etc. operations are implemented through the JVM, The interrupts in the AQS framework are placed in the Java implementation, regardless of the level of implementation, in the polling process must be able to ensure that there is no blocking. The second is to ensure that the granularity of the poll is as short as possible, which is related to the speed of interrupt response. The 3rd is about polling time node selection.
For three points, see how the AQS framework supports interrupts, mainly in the process of waiting for a lock to provide interrupt operations, the following is pseudo-code. Just add red and bold part of the logic to achieve interrupt support, in the loop body each cycle of the current thread interrupt identification bit to judge, once the thread is marked as broken to throw interruptedexception exception, high-level code on this exception capture processing is complete interrupt processing. Summed up is that the ASQ framework acquires the lock interrupt mechanism is implemented at the Java level, polling time node selection in the continuous attempt to acquire the lock operation, each cycle of the granularity is small, the response speed is guaranteed, and the cycle process is not the risk of blocking, to ensure that the interruption detection will not fail.
If (attempt to acquire lock failed) {
Create node
Using CAs to insert node into the tail of the queue
while (true) {
If (attempt to acquire the lock succeeds and node's predecessor is the head node) {
Set the current node as the head node
Jump out of the loop
}else{
Use CAs to modify node precursor nodes ' waitstatus identity as signal
If (Modify succeeded) {
Suspend current thread
if ( current thread interrupt bit ID is true)
Throw interruptedexception exception
}
}
}
It is very simple to determine whether a thread is in a broken state, just use the thread.interrupted () operation, or True to indicate that the thread is in the interrupt bit and clears the interrupt bit. This AQS implements a lock operation that supports interrupts.
This section analyzes preemptive interrupts and collaborative interrupts from the Java development process, because some of the pitfalls of preemption are now deprecated, and collaborative outages as a recommended practice, despite the long response time, has unparalleled advantages. Collaborative interrupts can be implemented at the JVM level, as well as at the Java level, such as the AQS framework is implemented at the Java level, but if you continue to drill down because Java leaves a few APIs for us to manipulate the thread's interrupt identity bits, this allows the Java plane to implement interrupt operations. Collaborative interrupt mechanism for Java Some people have been criticized for saying that there is no preemptive interrupt mechanism in Java, and that the collaborative interrupt mechanism forces developers to maintain the interrupt state, forcing developers to deal with Interruptedexception. However, it is believed that while the collaborative interrupt mechanism delays the processing of interrupt requests, it provides developers with a more flexible interrupt handling strategy that may be less responsive than preemptive, but more robust.
Support for Java concurrency Framework--aqs interrupts