等待-唤醒模型中,之前一直使用if进行条件判断是否达到阀值来进行阻塞,比如下面的例子
1 public class CoTest01 { 2 public static void main(String[] args) { 3 SynContainer container = new SynContainer(); 4 new Productor(container).start(); 5 new Consumer(container).start(); 6 // new Productor(container).start(); 7 // new Consumer(container).start(); 8 } 9 } 10 //生产者 11 class Productor extends Thread{ 12 SynContainer container ; 13 public Productor(SynContainer container) { 14 this.container = container; 15 } 16 17 public void run() { 18 //生产 19 for(int i=0;i<100;i++) { 20 container.push(new Steamedbun(i)); 21 } 22 } 23 } 24 //消费者 25 class Consumer extends Thread{ 26 SynContainer container ; 27 public Consumer(SynContainer container) { 28 this.container = container; 29 } 30 public void run() { 31 //消费 32 for(int i=0;i<100;i++) { 33 container.pop(); 34 } 35 } 36 } 37 //缓冲区 38 class SynContainer{ 39 List<Steamedbun> list=new ArrayList<>(); //存储容器 40 //存储 生产 41 public synchronized void push(Steamedbun bun) { 42 //何时能生产 容器存在空间 43 //不能生产 只有等待 44 if(list.size() == 10) { 45 try { 46 this.wait(); //线程阻塞 消费者通知生产解除 47 } catch (InterruptedException e) { 48 System.out.println("push 异常"); 49 } 50 } 51 //存在空间 可以生产 52 list.add(bun); 53 //存在数据了,可以通知消费了 54 this.notifyAll(); 55 System.out.println("生产第-->"+list.size()+"个馒头"); 56 } 57 //获取 消费 58 public synchronized void pop() { 59 //何时消费 容器中是否存在数据 60 //没有数据 只有等待 61 if(list.size() == 0) { 62 try { 63 this.wait(); //线程阻塞 生产者通知消费解除 64 } catch (InterruptedException e) { 65 } 66 } 67 //存在数据可以消费 68 list.remove(list.size()-1); 69 this.notifyAll(); //存在空间了,可以唤醒对方生产了 70 System.out.println("消费第" + list.size() + "个馒头"); 71 } 72 } 73 //馒头 74 class Steamedbun{ 75 int id; 76 public Steamedbun(int id) { 77 this.id = id; 78 } 79 80 }
这个例子是多个线程进行生产和消费馒头,馒头的个数不能小于0,大于10。
在44和61行使用的是if判断,此时main方法里创建的是两个线程,启动后发现并不会有异常。
但是在改成四个线程后就发生异常了
根据java8 api文档可知,可能会发生虚假唤醒,所以该方法应该始终在循环中使用。
Object 的 wait 方法
Condition 的 await 方法
在换成while后,一切正常。