等待-唤醒模型中,之前一直使用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 }1617 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 Syst3849em.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 }7980 }
这个例子是多个线程进行生产和消费馒头,馒头的个数不能小于0,大于10。
在44和61行使用的是if判断,此时main方法里创建的是两个线程,启动后发现并不会有异常。
但是在改成四个线程后就发生异常了
根据java8 api文档可知,可能会发生虚假唤醒,所以该方法应该始终在循环中使用。
Object 的 wait 方法
Condition的 await方法
在换成while后,一切正常。