我们知道,线程之间是抢占式执行的.通俗来说,就是随机调度的.每一个线程什么时候运行我们也不知道.
这里就来介绍,让线程可以按照一定顺序执行的方法.
目录
1.wait方法
方法 | 说明 |
wait() | 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法 |
wait(long timeout) |
导致当前线程等待,直到另一个线程调用notify()方法或该对象的 notifyAll方法,或者指定的时间已过 |
wait方法主要是让线程进入阻塞的状态,使其不能往下执行.
wait方法要搭配synchronized关键字,即锁来使用.
其还是一个object类方法,建议新创建一个object类单独搭配使用.
经过为:
- 使调用了这个方法的线程进入阻塞状态(进入等待队列中).
- 释放当前的锁.
- 等待别的线程调用notify方法将其唤醒,再重新获取此锁.
2.notify \ notifyAll方法
方法 | 说明 |
notify() | 唤醒正在等待对象监视器的单个线程 |
notifyAll() | 唤醒正在等待对象监视器的所有线程 |
(为了方便,除了特别说明.下文notify与notifyAll方法统称为notify方法)
notify\notifyAll方法,同样的搭配synchronized关键字来使用.
同样的也是object类方法.
唤醒在其他线程中调用notify方法,唤醒调用了同一个object类对象wait方法的线程.
经过为:
(背景: 此处的wait与notify方法在同一个类对象当中.且线程A调用了wait方法)
- 线程B调用了notify方法,发出了notify通知,通知线程A重新获取此object类对象的锁
- 使等待队列中的线程A得到唤醒.如果等待队列中有多个线程,则随机将其一唤醒.
- 线程B中执行完锁中的内容,使锁得到释放
- 此时线程A可以获取锁,可以执行下面的内容
3.使用wait与notify的注意事项
①wait与notify都为Object类的类方法
在与wait方法同一个object对象的notify方法才能将其唤醒
Object object = new Object();
object.wait();
object.notify();
②搭配synchronized关键字使用
使用synchronized关键字的理由,因为搭配使用的wait与notify方法放在同一个类对象中.
我们的期望是线程A在满足一定的条件下才调用wait方法,线程B又要判断一定的条件才去调用notify方法唤醒线程A.
但因为线程是抢占式的执行,对于哪一个线程先执行是随机的.
如果没有在synchronized修饰的代码块下:
- 线程A在判断条件决定要去执行wait方法但还没去来得及使用wait方法后.
- 这时调度到了线程B,线程B看到线程A没有进入阻塞状态认为其还没有达到wait的条件而去进行了其他的操作.
- 当又调度到了线程A的时候,这时线程A又进入到了阻塞的状态.
这显然不是我们期望看到的结果,如果使用了synchronized对其上锁.就不会发生这种多线程环境下的执行问题
③使用示例
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
//代码中的对象1,2,3,4是要同一个对象才能相应的有正确的效果.
// 如果四个对象任一不相同的话就会导致错误
Thread thread0 = new Thread(() -> {
synchronized (object){//此处的对象①
System.out.println("wait之前");
try {
object.wait();//此处的对象②
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait之后");
}
});
Thread thread1 = new Thread(() ->{
synchronized (object){//此处的对象③
System.out.println("notift之前");
object.notify();//此处的对象④
System.out.println("notify之后");
}
});
thread0.start();
Thread.sleep(1000);
thread1.start();
}