注意:
调用wait()、notify()方法时,当前线程必须要成功获得锁(必须写在同步代码块锁中),否则将抛出异常。
只对当前单个共享变量生效,多个共享变量需要多次调用wait()方法。
如果线程A调用wait()方法后处于堵塞状态时,其他线程中断(在其他线程调用A.interrupt()方法)A线程,则会抛出InterruptExcption异常而返回并终止。
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();
}
}
结果
线程Thread-0获得锁,进入等待状态
线程Thread-1获得锁,进入等待状态
线程Thread-2获得锁,开始通知唤醒所有线程
线程Thread-2执行结束
线程Thread-1执行最后部分结束
线程Thread-0执行最后部分结束
这个细节隐藏在Java的Native方法中,所以一般不会被人发现。我们观察C/C++源码,如下:
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();
}
其中ensure_join就是执行join()方法,等方法执行结束时,此行代码lock.notify_all(thread);意思是通过notifyAll()唤醒了所有等待线程。所以在使用线程的时候,要特别注意。
转载 https://blog.csdn.net/x541211190/article/details/109322537