线程的等待与唤醒
在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
Object类中关于等待/唤醒的API详细信息如下:
- notify():随机唤醒在此对象监视器上等待的单个线程。
- notifyAll():唤醒在此对象监视器上等待的所有线程。
- wait():让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
- wait(long timeout):让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
- wait(long timeout, int nanos):让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
示例1:wait() 和 notify()方法
public class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
public void run(){
synchronized (this){
System.out.println(Thread.currentThread().getName() + " call notify()");
//唤醒当前的wait线程
notify();
}
yield();
System.out.println(Thread.currentThread().getName() + " is running.");
}
public static void main(String[] args) {
ThreadA t1 = new ThreadA("t1");
ThreadA t2 = new ThreadA("t2");
synchronized (t1){
try{
//启动线程t1,t2
System.out.println(Thread.currentThread().getName() + " start t1");
t1.start();
System.out.println(Thread.currentThread().getName() + " start t2");
t2.start();
//主线程等待t1通过notify()唤醒
System.out.println(Thread.currentThread().getName() + " wait()");
t1.wait();
System.out.println(Thread.currentThread().getName() + " continue");
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
main start t1
main start t2
main wait()
t2 call notify()
t1 call notify()
main continue
t2 is running.
t1 is running.
几点说明:
- wait()是让“当前线程”等待
- wait() 相当于 wait(0)方法,表示无限等待
- “当前线程”在调用wait()方法时,必须拥有对象的同步锁,该线程调用完wait()方法后,释放该锁
==========
示例2:wait(long timeout) 方法
public class ThreadB extends Thread{
public ThreadB(String name){
super(name);
}
public void run(){
System.out.println(Thread.currentThread().getName() + " is running");
//无限循环
while(true)
;
}
public static void main(String[] args) {
ThreadB threadB = new ThreadB("threadB");
synchronized (threadB){
try {
//启动线程threadB
System.out.println(Thread.currentThread().getName() + " start threadB");
threadB.start();
//主线程等待threadB通过notify(),或notifyAll(),或超过3000ms; 唤醒
System.out.println(Thread.currentThread().getName() + " call wait");
threadB.wait(3000);
System.out.println(Thread.currentThread().getName() + " continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
main start threadB
main call wait
threadB is running
main continue
Process finished with exit code 130 (interrupted by signal 2: SIGINT)
==========
示例3:wait() 和 notifyAll()方法
public class NotifyAllTest {
private static Object obj = new Object();
static class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
public void run(){
synchronized (obj){
try{
System.out.println(Thread.currentThread().getName() + " wait");
//当前线程等待唤醒
obj.wait();
System.out.println(Thread.currentThread().getName() + " continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
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){
//主线程唤醒全部等待线程
System.out.println(Thread.currentThread().getName() + " notifyAll()");
obj.notifyAll();
}
}
}
运行结果:
t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue
几点说明:
负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。
notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。
网友评论