wait和notify方法用来实现一个线程需要等待另一个线程的执行结果的场景。
wait: 让当前线程在Monitor对象上等待,变成Waiting状态
notify:唤醒Monitor对象上等待的一个线程
notifyAll:唤醒Monitor对象上等待的全部线程
一、wait和notify方法的简单使用
假设有两个线程t1,t2,t1需要有烟才能干活,t2是来送烟的。
public class Test5 {
public static void main(String[] args) throws InterruptedException {
//是否有烟的标记,默认false
final boolean[] isHaveSmoke = {false};
Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
if (!isHaveSmoke[0]){
//没有烟时就等待
try {
//注意要在哪个锁对象上等待就要调用哪个对象的方法
//这里是lock上等待
//wait方法会释放锁
System.out.println("没烟开始等待");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有烟后继续干活
System.out.println("继续干活,烟的状态:"+ isHaveSmoke[0]);
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//线程t2来送烟,3s后把烟送到
try {
//注意sleep不会释放锁,所以不放在synchronized中,让其他线程有机会执行
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock){
System.out.println("烟送到了:");
isHaveSmoke[0] =true;
lock.notify();
}
}
},"t2");
t1.start();
t2.start();
}
}
上边这段代码演示了t1等待t2的结果后才能执行。
二、虚假唤醒问题
上边这段代码,如果还有一个线程t3在烟还没送到前就执行了notifyAll方法,t1就会被提前唤醒然后执行后边的逻辑
public class Test5 {
public static void main(String[] args) throws InterruptedException {
//是否有烟的标记,默认false
final boolean[] isHaveSmoke = {false};
Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
if (!isHaveSmoke[0]){
//没有烟时就等待
try {
//注意要在哪个锁对象上等待就要调用哪个对象的方法
//这里是lock上等待
//wait方法会释放锁
System.out.println("没烟开始等待");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有烟后继续干活
System.out.println("继续干活,烟的状态:"+ isHaveSmoke[0]);
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//线程t2来送烟,3s后把烟送到
try {
//注意sleep不会释放锁,所以不放在synchronized中,让其他线程有机会执行
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock){
System.out.println("烟送到了:");
isHaveSmoke[0] =true;
lock.notify();
}
}
},"t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
//睡1s是为了保证t1已经开始等待了
Thread.sleep(1000);
synchronized (lock){
System.out.println("t3唤醒全部线程");
lock.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t3");
t1.start();
t2.start();
t3.start();
}
}
为了展示烟的状态,我在t1干活时打印了烟的状态,可以看到t1确实是被虚假唤醒的。针对这种问题,因为if判断只有一次机会,所以t1被虚假唤醒后就不能再次判断烟的状态了,所以可以把if判断改成while,这样当t1被虚假唤醒后会再次循环检测烟的状态,如果烟还没到,t1就会继续等待。
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
while (!isHaveSmoke[0]){
//没有烟时就等待
try {
//注意要在哪个锁对象上等待就要调用哪个对象的方法
//这里是lock上等待
//wait方法会释放锁
System.out.println("没烟开始等待");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有烟后继续干活
System.out.println("继续干活,烟的状态:"+ isHaveSmoke[0]);
}
}
},"t1");
三、wait notify的原理
wait方法使用到了Monitor对象里的一个waitset属性,当一个线程调用了wait方法时就会进入Monitor的waitset进行等待,状态变成waiting并释放锁,当其他线程调用了唤醒方法后才会恢复执行。
四、保护性暂停
这是一种设计模式,用来让一个线程等待另一个线程的结果
public class Test6 {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("等待结果:");
Object response = guardedObject.getResponse(2000);
System.out.println("等到的结果:"+response);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("等待后设置结果");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedObject.setResponse("hello");
}
});
t1.start();
t2.start();
}
}
//这个对象用来在两个线程之间传递结果
class GuardedObject{
private Object response;
public synchronized void setResponse(Object response){
this.response =response;
}
//超过一定时间后就不再等待
public synchronized Object getResponse(long timeout){
//记录开始等待的时间
long start = System.currentTimeMillis();
long pastTime=0;//已经等待的时间
while (response==null){
if(pastTime- timeout>=0){
break;
}
try {
//只等待还剩下的还没等够的时间
wait(timeout-pastTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//等待结束时计算pastTime
pastTime=System.currentTimeMillis()-start;
}
return response;
}
}
注意 join方法的底层用的就是wait方法,就用了类似这样的一种等待方式
标签:Thread,lock,t1,线程,notify,new,方法,public,wait From: https://www.cnblogs.com/chengxuxiaoyuan/p/16860761.html