Introduction
This article will undertake the "Java multi-threaded wait() and notify() series of methods using tutorials" , combined with code examples, supplementary explanations of notifyAll()
the functions of the methods and the points that need to be paid attention to when using them.
1. Definition of notifyAll() method in JDK
notifyAll()唤醒正在等待此对象监视器锁的所有线程。
Notice:
The meaning in 1. notifyAll()
is All
that all threads, not all locks, can only wake up all threads waiting for the same lock (call wait() method to wait), which must be noted.
2. notifyAll()
Must be executed when the current thread owns the monitor lock, otherwise an exception will be thrown IllegalMonitorStateException
. It means that this method must be called in a synchronized code block, otherwise it may be executed without the lock, resulting in a program exception. wait()
And notify()
series methods are designed this way to prevent deadlocks or perpetual waits from occurring.
3. The notifyAll()
method can be called by any object, and this method cannot be overridden because it is final
decorated.
4. notifyAll()
Only one lock can be released. It is important to list this article separately.
5. notifyAll()
After execution, only one thread can get the lock, and other threads that do not get the lock will continue to wait in the waiting state.
2. Explain a standard notifyAll() method using code
Code logic description:
- Threads
thread0
andthread1
common contentionobject
object lock, and call their respectivewait()
methods to wait. - The thread
thread2
is responsible fornotifyAll()
waking up the thread.
public class ThreadWaitAndNotifyAll implements Runnable {
// 模拟多个线程的共享变量
private static Object object = new Object();
@Override
public void run() {
synchronized (object) {
System.out.println("线程" + Thread.currentThread().getName() + "获得锁,进入等待状态");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "执行最后部分结束");
}
}
public static void main(String[] args) {
ThreadWaitAndNotifyAll runnable = new ThreadWaitAndNotifyAll();
Thread thread0 = new Thread(runnable);
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程" + Thread.currentThread().getName() + "获得锁,开始通知唤醒所有线程");
// 唤醒其他线程
object.notifyAll();
// 调用完notifyAll()方法后,同步代码块中的其他代码,必须执行完后才能将对象锁释放,而不是调用了notifyAll()方法后立即释放。
System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
}
}
});
// 每次运行,线程0和线程1的顺序可能会不同,执行顺序由CPU决定
thread0.start();
thread1.start();
try {
// 加一个延时,让线程2一定在线程0和1之后执行,否则线程2中的notifyAll方法将无效
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
Results of the:
线程Thread-0获得锁,进入等待状态
线程Thread-1获得锁,进入等待状态
线程Thread-2获得锁,开始通知唤醒所有线程
线程Thread-2执行结束
线程Thread-1执行最后部分结束
线程Thread-0执行最后部分结束
Execute the result analysis:
thread0
Andthread1
after startup, each will execute its own code, and after thewait()
method is executed, it will enter the waiting state.thread2
Before starting, thesleep
delay is deliberately increased to ensure that the execution order is guaranteed to run after the first two threads.thread2
After thenotifyAll()
method is executed and thesynchronized
rest of the code block is executed, the CPU willobject
randomly assign the object lock tothread0
orthread1
(only one of the two can be selected).- If
thread1
the lock is obtained, it will continue to execute thewait()
code after its method, and the CPU will not assign the objectobject
lock to the waiting thread until the content of the synchronized code block is fully executedthread0
. thread0
After getting so, it will continue to execute from the method, and the lockwait()
on the object will not be released until the end of the synchronized code block .object
Note: After the method is called notifyAll()
, other codes in the synchronized code block must be executed before the object lock can be released, not notifyAll()
immediately after the method is called.
3. Very important hidden knowledge points about notifyAll()
In java, after the thread of Thread class executes the run() method, it will automatically execute the notifyAll() method.
This detail is hidden in Java's Native methods, so it is generally not discovered. We observe the C/C++ source code as follows:
oid JavaThread::exit(booldestory_vm, ExitTypeexit_type);
static void ensure_join(JavaThread*thread) {
Handle threadObj(thread, thread -> threadObj());
ObjectLocker lock(threadObj, thread);
thread -> clear_pending_exception();
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
java_lang_Thread::set_thread(threadObj(), NULL);
//下行执行了notifyAll()操作
lock.notify_all(thread);
thread -> clear_pending_exception();
}
Among them ensure_join
, the join() method is executed. When the method execution ends, this line of code lock.notify_all(thread);
means that notifyAll()
all waiting threads are woken up. So be careful when using threads.
Summarize
After explaining the notifyAll()
usage of the methods in this article, the notify
series of methods have been explained. In the next article, we will implement several important and specific scenarios to use these methods to do some things and see how these methods are often used. where. If you like this article, please continue to pay attention to follow-up articles as well as bookmark and like.