Java thread waiting and Java wake threads Java multithreading tutorial

  • 2020-04-01 02:44:03
  • OfStack

In this chapter, the thread wait/wake method is introduced. The contents involved include:
1. Method introduction of wait(), notify(), notifyAll(), etc
2. Wait () and notify ()
3. Wait (long timeout) and notify()
4. Wait () and notifyAll ()
5. Why are the functions notify(), wait() and so on defined in Object instead of Thread

Methods of wait(), notify(), notifyAll(), etc
In object.java, the interfaces wait(), notify(), and notifyAll() are defined. A wait() is used to put the current thread into a wait state, and a wait() is used to cause the current thread to release the lock it holds. Notify () and notifyAll() wake up the waiting thread on the current object. Notify () wakes up a single thread, while notifyAll() wakes up all threads.

The details of the wait/wake API in the Object class are as follows:
Notify ()               Wakes up a single thread waiting on this object monitor.
NotifyAll ()     Wakes up all threads waiting on this object monitor.
Wait ()                                                                                 -- leave the current thread in a "wait (blocking) state" until another thread calls the notify() or notifyAll() method of this object, and the current thread is awakened (into a "ready state").
Wait (long timeout)                                       -- leave the current thread in a "wait (blocking) state" until another thread calls the notify() or notifyAll() method of this object, or the specified amount of time is exceeded, and the current thread is awakened (into a "ready state").
Wait (long timeout, int nanos)   -- leave the current thread in a "wait (blocked) state" until another thread calls the notify() or notifyAll() method of this object, or some other thread interrupts the current thread, or a certain amount of time has passed, and the current thread is awakened (into a "ready state").


2. Examples of wait() and notify()
Here's an example of "wait() with notify()."


//WaitTest. Java source code
class ThreadA extends Thread{
    public ThreadA(String name) {
        super(name);
    }
    public void run() {
        synchronized (this) {
            System.out.println(Thread.currentThread().getName()+" call notify()");
            //Wakes up the current wait thread
            notify();
        }
    }
}
public class WaitTest {
    public static void main(String[] args) {
        ThreadA t1 = new ThreadA("t1");
        synchronized(t1) {
            try {
                //Start "thread t1"
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();
                //The main thread waits for t1 to wake up via notify().
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();
                System.out.println(Thread.currentThread().getName()+" continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Operation results:


main start t1
main wait()
t1 call notify()
main continue

Results:
The following figure illustrates the flow of "main thread" and "thread t1".

(01) notice that the "main thread" in the figure represents "main thread". Thread t1" represents the "thread t1" started in WaitTest. The "lock" represents the "synchronous lock of the object t1".
(02) "main thread" creates "thread t1" through new ThreadA("t1"). The "synchronized lock for a t1 object" is then acquired via synchronized(t1). Then call t1.start() to start "thread t1".
(03) the main thread executes t1.wait() to release the "lock on the t1 object" and enter the "wait(block) state". Waiting for a thread on a t1 object to wake up through notify() or notifyAll().
(04) after "thread t1" runs, acquire the "lock of the current object" through synchronized(this); Then call notify() to wake up the "waiting thread on the current object," or the "main thread."
(05) when "thread t1" is finished, release the "lock on the current object". Next, the "main thread" acquires the "lock on the t1 object" and runs on.

< img border = 0 id = theimg onclick = window. The open this. (SRC) SRC = "/ / files.jb51.net/file_images/article/201401/20140114101027.jpg? 2014014101059 ">


For the above code? A friend once asked: t1.wait() should be "thread t1" wait; But why let the main thread wait?
Before we answer that question, let's take a look at an introduction to wait in the JDK documentation:


Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. 
In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

Chinese:

Causes the current thread to wait until another thread calls notify() or notifyAll() to wake up the thread. In other words, this method works just as well as wait(0)! In addition, for the wait(long millis) method, when millis is 0, the wait is infinite until it is awakened by notify() or notifyAll().
When the current thread calls wait(), it must have a synchronization lock for that object. After the thread calls wait(), the lock is released; Then wait until "other threads" invoke the notify() or notifyAll() method of the object's synchronized lock. The thread then continues to wait until it reacquires the synchronization lock for the object, and then can proceed.
Note: in JDK interpretation, the effect of wait () is to make the "current thread" wait, and the "current thread" is the thread running on the CPU!
This also means that while t1.wait() is a wait() method called through "thread t1," t1.wait() is called in the main thread main. The main thread must be the "current thread", that is, the running state, to execute t1.wait(). So, the current thread is the main thread! So t1.wait() is for the "main thread" to wait, not the "thread t1"!


3. Wait (long timeout) and notify()
Wait (long timeout) puts the current thread in a "wait(blocking) state" until another thread calls the notify() or notifyAll() method of this object, or the specified amount of time is exceeded, and the current thread is awakened (into a "ready state").
The following example demonstrates a wait(long timeout) in which a thread is awakened in the case of a timeout.


//WaitTimeoutTest. Java source code
class ThreadA extends Thread{
    public ThreadA(String name) {
        super(name);
    }
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run ");
        //Dead loop, running.
        while(true)

    }
}
public class WaitTimeoutTest {
    public static void main(String[] args) {
        ThreadA t1 = new ThreadA("t1");
        synchronized(t1) {
            try {
                //Start "thread t1"
                System.out.println(Thread.currentThread().getName() + " start t1");
                t1.start();
                //The main thread waits for t1 to be awakened by notify() or notifyAll(), or to be delayed beyond 3000ms. Then he wakes up.
                System.out.println(Thread.currentThread().getName() + " call wait ");
                t1.wait(3000);
                System.out.println(Thread.currentThread().getName() + " continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Operation results:


main start t1
main call wait 
t1 run                  //In about three seconds... "The main output continue"
main continue

Results:
The following figure illustrates the flow of "main thread" and "thread t1".
(01) notice that the "main thread" in the figure represents the WaitTimeoutTest main thread. Thread t1" represents the thread t1 that was started in WaitTest. The "lock" represents the "synchronous lock of the object t1".
(02) the main thread executes t1.start() to start "thread t1".
(03) the main thread executes t1.wait(3000), at which point the main thread enters a "blocked state". The main thread needs to "wake up the thread for the t1 object lock through notify() or notifyAll()" or "timeout after 3000ms" before the main thread enters the "ready state" and can run.
(04) after "thread t1" runs, it enters a dead loop and runs continuously.
(05) after a timeout of 3000ms, the main thread enters the "ready state" and then the "run state".

< img border = 0 id = theimg onclick = window. The open this. (SRC) SRC = "/ / files.jb51.net/file_images/article/201401/20140114101017.jpg? 2014014101321 ">

4. Wait () and notifyAll ()
From the previous example, we learned that the notify() can wake up a single thread waiting on this object's monitor.
Next, we demonstrate the use of notifyAll() with an example; It wakes up all threads that are waiting on this object's monitor.


public class NotifyAllTest {
    private static Object obj = new Object();
    public static void main(String[] args) {
        ThreadA t1 = new ThreadA("t1");
        ThreadA t2 = new ThreadA("t2");
        ThreadA t3 = new ThreadA("t3");
        t1.start();
        t2.start();
        t3.start();
        try {
            System.out.println(Thread.currentThread().getName()+" sleep(3000)");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized(obj) {
            //The main thread waits for awakening.
            System.out.println(Thread.currentThread().getName()+" notifyAll()");
            obj.notifyAll();
        }
    }
    static class ThreadA extends Thread{
        public ThreadA(String name){
            super(name);
        }
        public void run() {
            synchronized (obj) {
                try {
                    //printout
                    System.out.println(Thread.currentThread().getName() + " wait");
                    //Wakes up the current wait thread
                    obj.wait();
                    //printout
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Operation results:


t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue

Results:
Refer to the flowchart below.
(01) new and started three threads "t1", "t2" and "t3" in the main thread.
(02) the main thread sleeps for 3 seconds through sleep(3000). While the main thread is sleeping for 3 seconds, we assume that "t1", "t2", and "t3" are all running. Take "t1" as an example. When it runs, it performs obj.wait() to wait for other threads to wake it up by notify() or nofityAll(). In the same way, "t2" and "t3" wait for other threads to wake them up via nofity() or nofityAll().
(03) after the main thread sleeps for 3 seconds, it continues to run. Execute obj.notifyAll() to wake up the waiting threads on obj, that is, to wake up the three threads "t1", "t2", and "t3". Immediately after the synchronized(obj) run of the main thread completes, the main thread releases the obj lock. This way, "t1", "t2" and "t3" can acquire the "obj lock" and continue running!

< img border = 0 id = theimg onclick = window. The open this. (SRC) SRC = "/ / files.jb51.net/file_images/article/201401/20140114100821.jpg? 2014014101411 ">


5. Why are the functions notify(), wait() and so on defined in Object instead of Thread
The wait(), notify() and other functions in Object, like synchronized, operate on the synchronized lock of the Object.

Wait () causes the "current thread" to wait, because the thread is in the wait state, so the thread should release the "synchronized lock" it holds, otherwise other threads cannot acquire the "synchronized lock" and cannot run!
OK, after the thread calls wait(), it releases the "synchronized lock" it holds. Also, from the previous introduction, we know that waiting threads can be awakened by notify() or notifyAll(). Now, consider the question: on what basis does notify() wake up a waiting thread? Or, what is the connection between a wait() wait thread and a notify()? The answer is: according to the "synchronized locking of the object."

The thread responsible for waking up the waiting thread (we call it the "waking thread") can only wake up the waiting thread after it has acquired the synchronization lock for the object (the synchronization lock here must be the same as the synchronization lock for the waiting thread) and has called the notify() or notifyAll() method. While waiting for the thread to be awakened; However, it cannot be executed immediately because the wake thread also holds a "synchronized lock for this object." You must wait for the wake thread to release the synchronization lock of the object before the thread can acquire the synchronization lock of the object and continue running.

In short, notify(), wait() depends on a "sync lock," which is held by an object lock and has one and only one per object! This is why the notify(), wait() and other functions are defined in the Object class, not in the Thread class.


Related articles: