wait、notify和notifyAll的使用
首先,wait、notify和notifyAll 这三个 都是Object类里的方法,可以用来控制线程的状态
解释:
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
下来有个生产者消费者的列子, 提供理解:
package com.luxins.join.join; import java.util.Queue; public class Consumer implements Runnable { //背包 Queue<String> bages; //大小 int size; public Consumer(Queue<String> bages, int size) { this.bages = bages; this.size = size; } @Override public void run() { while (true) { synchronized (bages) { while (bages.isEmpty()) { try { System.out.println("背包满了了"); bages.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //睡眠1s try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String bage = bages.remove(); System.out.println("当前消费者的数量为:" + bage); //唤醒生产者(因为是双向的,又是同一个对象bages下) bages.notifyAll(); } } } }
package com.luxins.join.join; import java.util.Queue; public class producer implements Runnable { Queue<String> bages; int size; public producer(Queue<String> bages, int size) { this.bages = bages; this.size = size; } @Override public void run() { int i = 0; while (true) { i++; synchronized (bages) { while (bages.size() == size) { System.out.println("背包已经装满了"); try { bages.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前生产者数量为:"+i); bages.add("bages"+i); //唤醒消费者 bages.notifyAll(); } } } }
package com.luxins.join.join; import java.util.LinkedList; import java.util.Queue; public class TestMain { public static void main(String[] args) { Queue<String> a = new LinkedList<>(); int size = 10; Consumer consumer = new Consumer(a, size); producer producer = new producer(a, size); Thread t1 = new Thread(consumer); Thread t2 = new Thread(producer); t2.start(); t1.start(); } }
做多 10条,可能在没满 10之前 ,就已经 用了
情况是随机的
还有就是不一定就是生产一条 一定会消费一条
有可能生产了两条 只消费一条 然后继续生产
cup 不同,在不同电脑上出现的 效果 就不一样
这个例子就是
我们在调用wait()方法的时候,心里想的肯定是因为当前方法不满足我们指定的条件,因此执行这个方法的线程需要等待直到其他线程改变了这个条件并且做出了通知。
那么为什么要把wait()方法放在循环而不是if判断里呢,其实答案显而易见,因为wait()的线程永远不能确定其他线程会在什么状态下notify(),
所以必须在被唤醒、抢占到锁并且从wait()方法退出的时候再次进行指定条件的判断,以决定是满足条件往下执行呢还是不满足条件再次wait()呢。
就像在本例中,如果只有一个生产者线程,一个消费者线程,那其实是可以用if代替while的,因为线程调度的行为是开发者可以预测的,
生产者线程只有可能被消费者线程唤醒,反之亦然,因此被唤醒时条件始终满足,程序不会出错。
但是这种情况只是多线程情况下极为简单的一种,更普遍的是多个线程生产,多个线程消费,
那么就极有可能出现唤醒生产者的是另一个生产者或者唤醒消费者的是另一个消费者,这样的情况下用if就必然会现类似过度生产或者过度消费的情况了,
典型如IndexOutOfBoundsException的异常。所以所有的java书籍都会建议开发者永远都要把wait()放到循环语句里面。