最近在学习线程,发现一个有意思的面试题,wait为什么用while而不能用if?
这个是一个固定容量同步容器,拥有put和get方法
package yxxy.c_021;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
public class MyContainer1<T> {
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10; //最多10个元素
private int count = 0;
public synchronized void put(T t) {
while(lists.size() == MAX) { //为什么用while而不是用if?
try {
this.wait(); //effective java
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lists.add(t);
++count;
this.notifyAll();
}
public synchronized T get() {
T t = null;
while(lists.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t = lists.removeFirst();
count --;
this.notifyAll();
return t;
}
public static void main(String[] args) {
MyContainer1<String> c = new MyContainer1<>();
//启动消费者线程
for(int i=0; i<10; i++) {
new Thread(()->{
for(int j=0; j<5; j++) System.out.println(c.get());
}, "c" + i).start();
}
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
//启动生产者线程
for(int i=0; i<2; i++) {
new Thread(()->{
for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
}, "p" + i).start();
}
}
}
如果有n个生产者,n个消费者。当存储空间满了之后,假如n(大于1个)个生产者被wait,进入等待唤醒队列。当某个消费者取走了一个数据后,如果调用notifyAll(),则n个生产者线程都将被唤醒,如果此时生产者线程中的wait不在while循环中而是在if中,则这些生产者线程就不会再次判断是否符合执行条件,都将直接执行wait()之后的程序,那么如果其中一个生产者线程放入了一个数据至存储空间,则此时存储空间已经满了;但是其他生产者线程还是会继续往存储空间里放数据,错误便产生了。
最后我也总结了while和if的区别
while和if本身就用法不同,一个是循环语句,一个是判断语句。
if 只做判断,判断一次之后,便不会再回来了
while 的话,循环,直到结果为false,才跳出来