Thread state
For the thread state in Java, the JVM has a clear statement: the thread state in the virtual machine does not reflect the thread state in any operating system. The JVM has its own set of specifications in design and should not be confused with the thread state at the bottom of the operating system.
Java Thread State is represented by the internal class State of Thread, which specifies the following six states;
state meaning NEW A new thread object has been created, but the start() method has not been called yet RUNNABLE In the RUNNABLE state, after the thread object calls the start() method, it will migrate from the NEW state to the RUNNABLE state BLOCKED Blocking status indicates that the thread is waiting for a monitor lock, and the embodiment of the monitor lock in Java code is the synchronized keyword; That is, the thread is in the BLOCKED state only when it is waiting to enter the synchronized modified code block or method WAITING Wait status indicates that the thread is waiting for some conditions to arrive TIMED_WAITING The timeout WAITING state is similar to the WAITING state, and the timeout limit is added on its basis TERMINATED Termination status, including normal thread execution completion and abnormal terminationThe flow between thread states is as follows:
RUNNABLE
- The RUNNABLE state indicates that it is running or ready to run. This state is relative to the JVM, and when the thread runs depends on the resource scheduling at the bottom of the operating system; Note that at the bottom of the operating system, running and ready to run are two different states, but the JVM level does not subdivide these two states
- When the yield operation is executed, the underlying state does change. The thread will give up the current execution right so that the CPU can execute other RUNNABLE threads. This is the underlying change, but at the JVM level, the original thread is still in the RUNNABLE state
Difference between BLOCKED and WAITING status
- The BLOCKED status indicates that a monitor lock is waiting, that is, the virtual machine thinks that the program cannot enter an area yet, because there will be problems when entering at the same time. This is a critical area
- The precondition of WAITING state is that the thread has entered the critical zone, that is, the thread has got the lock, but for other reasons, wait here
- In short, a thread will enter the BLOCKED state only when it waits to enter the synchronized code block or method; In addition, note that for locks implemented under the Lock interface, since the underlying layer calls the methods in LockSupport, waiting or timed is entered when waiting for the Lock_ WAITING
Thread method
Thread wait- The wait() method is located in the Object class. As mentioned earlier, the precondition for entering the wait state is that the lock of the Object has been obtained, so this method can only be used in the synchronization code
- When this method is called, the current thread enters the WAITING state. It will not return until it waits for the notification of other threads or the current thread is interrupted
- Call the wait() method, and the thread will release the lock; If the lock is not released, other threads cannot obtain the lock of the current object, and the notify/notifyAll method cannot be executed to wake up the suspended thread, resulting in deadlock
- The sleep() method is in the Thread class
- The sleep() method will not release the lock of the current object. It can only wait for the time to wake up naturally and complete the execution before other threads can continue to obtain the lock of the current object
What is the difference between wait and sleep?
- These two methods come from different classes. wait() acts on the resource object itself and sleep() acts on the current thread
- The most important thing is that the wait() method will release the lock, while sleep() will not release the lock
- The scope of use is different. wait() must be used in the synchronization code, and sleep() can be used anywhere (this also confirms the second point. Sleep has no lock to release)
- yield will make the current thread give up the CPU execution time slice, that is, pause, and let the system's thread scheduler reselect a runnable thread for execution
- Note that after the current thread calls the yield method, the final selection result may still be that the current thread continues to execute; Generally, threads with high priority are more likely to successfully compete for CPU time slices, but this is not absolute. Some operating systems are not sensitive to thread priority
- Note that thread interruption does not mean to stop the thread work immediately, because forcibly stopping a thread may cause unpredictable consequences, but some scenarios need to stop the thread, and thread interruption can meet these usage scenarios; Its usage scenario is similar to the following: in the A thread, calling the B thread's interupt() method is equivalent to calling the B thread and giving an interrupt mark to the B thread. In the B thread, isInterrupted() or interrupted() can be called to determine whether there is any thread that he wants to interrupt himself. According to the result of the judgment, the B thread can decide for itself how to do next.
- The following three methods are the most important for thread interruption:
- Interrupt(): interrupt the target thread, send an interrupt signal to the target thread, and the target thread is marked with an interrupt flag
- isInterrupted(): determines whether the thread is interrupted and does not clear the interrupt flag
- interrupted(): judge whether the thread is interrupted, and the interrupt flag will be cleared
- When calling a thread interrupt, if the thread is in the state of blocking, deadline waiting or indefinite waiting, an InterruptedException will be thrown and the interrupt ID will be cleared; However, I/O blocking and synchronized lock blocking cannot be interrupted
- Note that thread interrupt is a cooperation mechanism between threads. If you don't understand what the thread is doing, you shouldn't call the thread interrupt method rashly, thinking that this will cancel the thread
public static void main(String[] args) throws InterruptedException { Thread A = new Thread(() -> { // Judge whether it is interrupted while (!Thread.currentThread().isInterrupted()) { System.out.println(" A:study java in..."); } System.out.println("A:I hear someone wants to interrupt me? Finish learning js besides"); // Similarly, the interrupt ID is returned and cleared boolean interrupted = Thread.interrupted(); System.out.println("A:Current interrupt ID:" + interrupted + ", Clear, ignore and continue learning"); boolean b = Thread.currentThread().isInterrupted(); System.out.println("A:Identification after clearing:" + b + ", You can study at ease"); // Judge whether it is interrupted while (!Thread.currentThread().isInterrupted()) { System.out.println(" A:study js in..."); } System.out.println("A:Want to interrupt me again, Then take a break"); }, "A"); A.start(); try catch (InterruptedException e) {} // Interrupt thread A and don't indulge in learning A.interrupt(); try catch (InterruptedException e) {} // Continue interrupt A.interrupt(); }
Execution results:
A:study java in... A:study java in... A:study java in... A:study java in... A:I hear someone wants to interrupt me? Finish learning js besides A:Current interrupt ID: true, Clear, ignore and continue learning A:Identification after clearing: false, You can study at ease A:study js in... A:study js in... A:study js in... ... A:Want to interrupt me again, Then take a breakThread wait (join)
- The scenario is as follows: in the A thread, the join() method of the B thread is invoked, and the A thread must wait for the execution of the B thread to complete.
- Note that when calling the join() method of thread B, thread B needs to be started, otherwise it will be invalid. This is easy to see from the source code of the join() method
public static void main(String[] args) throws InterruptedException { Thread a = new Thread(() -> { System.out.println("a Start execution"); sleep(3); System.out.println("a completion of enforcement"); }); Thread b = new Thread(() -> { try { System.out.println(" b Start execution"); a.join(); System.out.println(" b Execution complete"); } catch (InterruptedException e) { e.printStackTrace(); } }); a.start(); sleep(1); b.start(); }
Execution results:
a Start execution b Start execution a completion of enforcement b Execution completeThread wakeup (notify/notifyAll)
- It is usually used in conjunction with the wait() method to wake up the waiting thread to continue execution; This is also in the Object class
- Note that calling the notify/notifyAll method does not release the object lock
The general process is as follows:
Code example:
public static void main(String[] args) throws InterruptedException { Object obj = new Object(); Thread A = new Thread(() -> { synchronized (obj) { System.out.println("A:Get the lock first, Play for two seconds"); sleep(2); try { System.out.println("A:Enter the waiting queue"); obj.wait(); System.out.println("A:Awakened, bye-bye"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A"); Thread B = new Thread(() -> { System.out.println(" B:Lock quilt A occupy, Wait"); synchronized (obj) { System.out.println(" B:thread A Waiting to go,I got the lock, Play for two seconds"); sleep(2); System.out.println(" B:awaken A"); obj.notify(); System.out.println(" B:Although I wake up A, But I keep playing, A I didn't get the lock, Still unable to execute, A Thread state:" + A.getState()); sleep(2); System.out.println(" B:It's over, bye-bye"); } }, "B"); A.start(); sleep(1); B.start(); } private static void sleep(int seconds) { try { TimeUnit.SECONDS.sleep(seconds); } catch (InterruptedException e) { e.printStackTrace(); } }
Execution results:
A:Get the lock first, Play for two seconds B:Lock quilt A occupy, Wait A:Enter the waiting queue B:thread A Waiting to go,I got the lock, Play for two seconds B:awaken A B:Although I wake up A, But I keep playing, A I didn't get the lock, Still unable to execute, A Thread state:BLOCKED B:It's over, bye-bye A:Awakened, bye-bye
deadlock
Example:Deadlock describes that multiple threads enter the blocking state because they want to obtain the object lock, and this state cannot be recovered by themselves, blocking indefinitely;
As shown in the following figure, threads A and B are blocked because they want to obtain an object lock, but they cannot obtain it. It is like forming A circle and falling into an endless loop
Code example:
public static void main(String[] args) throws InterruptedException { Object obj1 = new Object(); Object obj2 = new Object(); Thread A = new Thread(() -> { synchronized (obj1) { System.out.println("A Get obj1 Lock of"); sleep(2); System.out.println("A Want to get obj2 Lock of"); synchronized (obj2) { System.out.println("A Obtained obj2 Lock of"); } System.out.println("A No more"); } }, "A"); Thread B = new Thread(() -> { synchronized (obj2) { System.out.println("B Get obj2 Lock of"); sleep(2); System.out.println("B Want to get obj1 Lock of"); synchronized (obj1) { System.out.println("B Obtained obj1 Lock of"); } System.out.println("B No more"); } }, "B"); A.start(); B.start(); }
Operation results:
A Get obj1 Lock of B Get obj2 Lock of A Want to get obj2 Lock of B Want to get obj1 Lock of
At this time, it will be found that the program has not finished running and will not end. It is easy to see that thread A is stuck in the lock that wants to obtain obj2. On the contrary, thread B is deadlocked and cannot recover itself
Four conditions for deadlock in eight part essay:- Mutually exclusive condition: the resource is occupied by only one thread at any time
- Request and hold condition: when a process is blocked by requesting resources, it will hold the obtained resources
- No deprivation condition: the resources obtained by a thread cannot be forcibly deprived by other threads before they are used up. The resources can be released only after they are used up
- Circular waiting condition: a circular waiting resource relationship is formed between several threads
That is to destroy one of the four conditions for deadlock; Generally speaking, there are the following methods:
- Obtain resources in order. Since thread A obtains obj1 first and then obj2, thread B can also obtain resources in this order, so there will be no deadlock
- To actively release resources, thread A can choose to try to obtain the lock of obj2 first. If it fails to obtain the lock, do what it should do. Don't block it, and then release the lock of obj1 occupied by itself
- Apply for all resources at one time. Thread A can obtain the locks of obj1 and obj2 at the beginning and release them at the end. There will be no deadlock