复习时可参考JUC脑图,时间关系,先不整理这款代码实现
三种线程通知与等待的方法
- 使用Object中的wait()方法让线程等待,使用Object中的notify() / notifAll()方法通知线程
注意:在执行notify方法后,当前线程不会马上释放该对象锁,处于wait状态的线程也不能马上获取该对象锁。要等到执行notify方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁
Java中的Object类是所有类的父类,Object类包含所有子类需要的方法,如wait/notify/notifyAll等方法
- 使用JUC包中Condition的await()方法让线程等待,使用signal() / signalAll()方法通知线程
- LockSupport类中的park阻塞当前线程以及upark唤醒指定被阻塞的线程
Object类相关API
假设共享变量为Object obj = new Object();
wait
- 什么时候会阻塞?
当一个线程t1调用共享变量obj的wait()方法时,该线程t1会被阻塞 - 什么时候会从阻塞状态变为非阻塞状态?
其他线程main 调用该共享变量obj的nofify()或notifyAll()方法
其他线程main 调用该线程t1的interrupt()方法,该线程t1会抛InterruptedException异常返回。
public class WaitNotifyInterrupt {
static Object object = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(()->{
System.out.println("t1 begin");
synchronized (object) {
try {
object.wait();
System.out.println("t1 end");//中断后,这行代码不执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main start. interrupt t1");
t1.interrupt();
System.out.println("main end. interrupt t1");
}
}
执行结果:
wait(long timeout)
如果一个线程t1调用共享对象obj的wait(3000)方法后,也就是3秒内如果还没有被其他线程main对该共享变量obj的notify或notifyAll调用,那么wait(3000)会3秒后不会阻塞,继续往下执行
public class WaitNotifyInterrupt2 {
static Object object = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(()->{
System.out.println("t1 begin");
synchronized (object) {
try {
object.wait(3000);
System.out.println("t1 end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
}
}
执行结果:
t1 begin
t1 end //3秒后执行
notify()
一个线程调用共享对象的notify方法后,会唤醒一个在该共享变量上调用wait系列方法后的线程。一个共享变量可能会有多个线程在等待,具体唤醒哪个等待的线程是随机的。
注意:被唤醒后的线程,必须在获取共享变量的监视器锁后才能真正解除阻塞状态。被唤醒后的线程,还是需要与其他线程一起竞争该锁
notifyAll()
唤醒所有在该共享变量上调用wait系列方法后处于阻塞状态的线程。