Explain the wait notify mechanism of Java program concurrency in detail
Wait notify scenario a typical wait notify scenario is generally related to the following two contents: 1 State variable: when a thread needs a wait, it is always caused by some conditions that cannot be met. For example, when filling the queue with data, when the queue element is full, the thread needs to wait to stop running. When the queue element is vacant, it will continue its own execution. 2. Condition assertion (condition predict) when a thread determines whether to enter the wait or whether to continue to execute when it wakes up from notify, most of them need to test whether the status conditions are met. For example, if an element is added to the queue, the queue is full, so the current thread is blocked. When another thread takes an element from the queue, it notifies the waiting thread There is room left in the queue. You can add elements to it. At this time, the process waiting to add elements will be awakened, and then judge whether the current queue really has residual space. If there is residual space, add elements. If not, continue blocking and wait for the next wake-up. 3. Condition queue each object has a built-in condition queue. When a thread calls the wait function on the object lock, it will add the thread to the condition queue of the object.
Note that wait and notify are important components of Java synchronization mechanism. Combined with the synchronized keyword, many excellent synchronization models can be established, such as producer consumer model. However, when using the wait(), notify(), and notifyall() functions, you should pay special attention to the following points:
The wait(), notify(), and notifyall() methods do not belong to the thread class, but belong to the basic object class, that is, each object has the functions of wait(), notify(), and notifyall(). Because each object has a lock, and the lock is the basis of each object, the method of operating the lock is also the most basic. Before calling the wait() notify() method of obj, the obj lock must be obtained, that is, it must be written in synchronized (obj) {...} Within the code snippet. Call obj After wait(), thread a releases the obj lock. Otherwise, thread B cannot obtain the obj lock and cannot synchronize (obj) {...} Wake up thread a in the code segment. When obj After the wait () method returns, thread a needs to obtain the obj lock again to continue execution. If threads A1, A2 and A3 are all in obj Wait(), thread B calls obj Notify() can only wake up one of threads A1 and A3 (which is determined by the JVM). If thread B calls obj. Notifyall(), it can wake up all waiting threads A1 and A3, but the waiting thread should continue to execute obj The next statement of wait() must obtain the obj lock. Therefore, only one thread A1 and A3 has the opportunity to obtain the lock to continue execution. For example, A1 needs to wait for A1 to release the obj lock before continuing execution. When thread B calls obj Notify() or obj When notifyall(), thread B is holding the obj lock. Therefore, although threads A1 and A3 are awakened, they still cannot obtain the obj lock. Until thread B exits the synchronized code block and releases the obj lock, one of threads A1 and A3 has a chance to obtain the object lock and continue execution.
The typical code structure of the wait operation of the sample code thread is as follows:
Why obj Must the wait () operation be in a loop? There are the following main reasons: 1 An object lock may be used to protect multiple state variables. When they all need a wait notify operation, there will be a problem if you don't put wait in the while loop. For example, an object lock obj protects two state variables A and B. when the conditional assertion of a is not true, a wait operation occurs. When the conditional assertion of B is not true, a wait operation also occurs. The two threads are added to the condition queue corresponding to obj. Now, if an operation to change the state variable a occurs and the notifyAll operation is called on obj, all threads in the condition queue corresponding to obj will be awakened. One or more threads waiting for a may judge that the condition assertion of a is true, but the condition assertion of B is certainly not true, and the thread waiting for B will also be awakened, Therefore, it is necessary to judge whether the conditional assertion of B is satisfied. If not, continue to wait. 2. Conditional assertion of the same state of multiple threads wait. For example, in the scenario of adding elements to the queue, the current queue is full, and multiple threads want to add elements to it, so they all wait. At this time, another thread takes an element from the queue, calls the notifyAll operation, and wakes up all threads. However, only one thread can add an element to the queue, and others still need to wait. 3. False awakening. The thread wakes up automatically without being notified, interrupted, or timed out. Although this situation rarely occurs in practice, it can be eliminated through circular waiting.