package example;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
public class MyContainer3<T> {
final private LinkedList<T> lists = new LinkedList<T>();
final private int MAX = 10; //最多10個(gè)元素
private int count = 0;
public synchronized void put(T t){
while(lists.size()==MAX){
try {
this.wait(); //wait 99%和while結(jié)合使用帘营,而不是和if結(jié)合使用
//容器滿了票渠,在這里wait,被叫醒時(shí)芬迄,直接是往下執(zhí)行的问顷,還沒運(yùn)行到往里扔的適合,另外一個(gè)線程往里扔了禀梳,導(dǎo)致出錯(cuò)杜窄。
//如果用while時(shí),他會(huì)繼續(xù)再檢查一遍算途,醒了的時(shí)候塞耕,再檢查一遍。 notifyAll可以叫醒多個(gè)線程郊艘。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lists.add(t);
count++;
this.notifyAll();
}
public synchronized T get(){
while(lists.size()==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
T t = lists.removeFirst();
count--;
/**注意喚醒*/
this.notifyAll();
return t;
}
public static void main(String[] args) {
MyContainer3<String> c = new MyContainer3<>();
//啟動(dòng)消費(fèi)者線程
for(int i=0; i<10; i++) {
new Thread(()->{
for(int j=0; j<5; j++) System.out.println(Thread.currentThread().getName() +"--"+c.get());
}, "c" + i).start();
}
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
//啟動(dòng)生產(chǎn)者線程
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();
}
}
}
面試點(diǎn):關(guān)于為什么用while 而不用if
wait 99%和while結(jié)合使用荷科,而不是和if結(jié)合使用
容器滿了,然后空了一個(gè)纱注,此時(shí)有兩個(gè)線程都醒了,他們都要爭(zhēng)取到那一把鎖畏浆,結(jié)果t2把那把鎖搶到了,然后它向容器里放了容器狞贱,此時(shí)當(dāng)t1再次被獲得鎖時(shí)刻获,它就不會(huì)檢查容器的容量,而繼續(xù)向下執(zhí)行瞎嬉,導(dǎo)致出錯(cuò)蝎毡,如果用while的話厚柳,它會(huì)回到上面再檢查一次,然后睡眠沐兵。
面試點(diǎn):為什么用notifyAll 而不用notify?
因?yàn)槿绻a(chǎn)者生產(chǎn)滿了容器后别垮,它notify的另外一個(gè)線程也是生產(chǎn)者,結(jié)果他去運(yùn)行的時(shí)候扎谎。也直接wait了碳想,這個(gè)時(shí)候,程序就死了毁靶,因?yàn)樗械木€程都睡了胧奔。
effective java 永遠(yuǎn)不要去使用notify而使用notifyAll