wait()和notify()是进行线程间通讯的两个重要的方法。
1.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)
2.notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的
线程。
3.wait(long timeout)让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态“)
一、wait()方法
其实wait()方法就是使线程停止运行。
1.方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法是用来将当前线程。置入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。
2.wait()方法只能在同步方法中或同步块中调用。如果调用wait()时,没有持有适当的锁,会抛出异常。
3.wait()方法执行后,当前线程释放锁,线程与其它线程竞争重新获取锁。
4.wait()方法必须和synchronized搭配使用,在进入线程等待前,必须要获得这个锁对象的控制权,一般情况下是放到synchronized(obj)块当中去,如果不加锁,就会出现IllegalMonitorStateException异常。
补充:wait()方法一般是对象调用的,this.wait()或者object.wat(),但是这里不是让这个对象等,而是让访问这个对象的线程等待,所以在多线程中,在调用wait(),让此刻访问对象的线程等待之前,不先获取对象锁(synchronized(obj))的控制权的话,由于在同一时刻或者同一时间段访问这个对象的有多个线程的话就会出错(IllegalMonitorStateException),这个异常出现的原因是:抛出以表示线程已尝试在对象的监视器上等待或通知其他线程等待对象的监视器,而不拥有指定的监视器。就是说当前的线程不是此对象锁的所有者,假如说本来对象是要通知线程1等待,结果来的是线程3或者线程4.并不是通知的那个线程,那么就会出现这个异常。
5.如果需要用上判断语句,应该使用的是while循环,而不是使用if语句下用wait(),这样,会在线程暂停恢复后都会检查一下wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。
二、notify()方法
当对象调用了wait()方法之后,那么此时访问这个对象的线程就会一直处于等待状态, 那么就会造成一个问题,程序还在运行,却没有任何的输出,所有线程都处于等待状态,这是一种“假死”状态,所以就需要用notify()方法来唤醒等待的线程继续执行任务,所以notify方法就是使停止的线程继续运行。
1.方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程。
2.在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
3.notify方法也是对象调用的方法,是让访问这个对象正在等待的线程重新恢复运行。
三、notifyAll()方法
用法和notify一直,但是notify方法只是唤醒某一个等待线程,那么如果有多个线程都在等待中怎么办呢,这个时候就可以使用notifyAll方法可以一次唤醒所有的等待线程,
四、应用实例,生产者消费者模型
public class Notify {
private static volatile int COUNT;
public synchronized static void produce(){
COUNT+=3;
}
public synchronized static void consume(){
COUNT-=3;
}
public static void main(String[] args) {
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true){
for(int j=0;j<10;j++){
synchronized (Notify.class){
while (COUNT+3>100){
Notify.class.wait();
}
produce();
System.out.println(Thread.currentThread().getName()+"生产,库存容量为:"+COUNT);
Thread.sleep(100);
Notify.class.notifyAll();
}
}
}
}catch (InterruptedException r){
r.printStackTrace();
}
}
}).start();
}
for(int i=0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
try{
while (true){
synchronized (Notify.class){
while (COUNT==0){
Notify.class.wait();
}
consume();
System.out.println(Thread.currentThread().getName()+"消费,库存总量为:"+COUNT);
Thread.sleep(100);
Notify.class.notifyAll();
}
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}).start();
}
}
}
运行结果:
Thread-0生产,库存容量为:3
Thread-0生产,库存容量为:6
Thread-0生产,库存容量为:9
Thread-0生产,库存容量为:12
Thread-0生产,库存容量为:15
Thread-0生产,库存容量为:18
Thread-0生产,库存容量为:21
Thread-0生产,库存容量为:24
Thread-0生产,库存容量为:27
Thread-0生产,库存容量为:30
Thread-0生产,库存容量为:33
Thread-0生产,库存容量为:36
Thread-0生产,库存容量为:39
Thread-0生产,库存容量为:42
Thread-0生产,库存容量为:45
Thread-9消费,库存总量为:42
Thread-9消费,库存总量为:39
Thread-10消费,库存总量为:36
Thread-10消费,库存总量为:33
Thread-10消费,库存总量为:30
Thread-10消费,库存总量为:27
Thread-10消费,库存总量为:24
Thread-10消费,库存总量为:21
Thread-10消费,库存总量为:18
Thread-10消费,库存总量为:15
Thread-10消费,库存总量为:12
Thread-11消费,库存总量为:9
Thread-11消费,库存总量为:6
Thread-11消费,库存总量为:3
Thread-11消费,库存总量为:0
Thread-1生产,库存容量为:3
Thread-1生产,库存容量为:6
Thread-1生产,库存容量为:9
Thread-1生产,库存容量为:12
Thread-1生产,库存容量为:15
Thread-1生产,库存容量为:18
Thread-1生产,库存容量为:21
Thread-1生产,库存容量为:24
Thread-1生产,库存容量为:27
Thread-1生产,库存容量为:30
Thread-1生产,库存容量为:33
Thread-1生产,库存容量为:36