本文共 2594 字,大约阅读时间需要 8 分钟。
目录
当一个条件满足时,很多线程都被唤醒了,但是只有其中部分是有用的唤醒,其它的唤醒都是无用功1.比如说买货,如果商品本来没有货物,突然进了一件商品,这是所有的线程都被唤醒了 ,但是只能一个人买,所以其他人都是假唤醒,获取不到对象的锁
例如在多线程的场景中,判断一个线程是否需要阻塞(调用wait())时,如果用 if 判断,就会出问题,因为想想看,多有多个线程都在阻塞时,突然条件满足了(product<1),那么就会有线程唤醒阻塞着的多个线程,但是只有一个线程能拿到锁,其余没拿到锁的线程要是被唤醒了,还继续往下执行,就不对了。
if(product>=1){ wait(); }
所以解决方法是 调用wait的代码块,要用while 来代替 if :
while(product>=1){ wait(); }
因为if只会执行一次,执行完会接着向下执行if()外边的 而while不会,直到条件满足才会向下执行while()外边的
把 while (product >=1) {} 换成 if (product >=1) {} 就会出现虚假唤醒
下面给个 生产者消费者的代码展示:
public class Test { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer producer = new Producer(clerk); Customer customer = new Customer(clerk); new Thread(producer,"生产者A").start(); new Thread(customer,"消费者A").start(); new Thread(producer,"生产者B").start(); new Thread(customer,"消费者B").start(); }}class Clerk{ private int product=0; public synchronized void add(){ while(product>=1){ System.out.println(Thread.currentThread().getName()+"---还有货物:"+product); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } product+=1; System.out.println(Thread.currentThread().getName()+" 补货完成,剩余货物:"+product); notifyAll(); } public synchronized void sale(){ while (product<=0){ System.out.println(Thread.currentThread().getName()+" 缺货中:"+product); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+" 已补货,开始消费..."); product-=1; notifyAll(); }}class Producer implements Runnable{ private Clerk clerk; public Producer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { for (int i=0;i<20;i++){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.add(); } }}class Customer implements Runnable{ private Clerk clerk; public Customer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.sale(); } }}
转载地址:http://lofh.baihongyu.com/