题目:
* 题目:现在两个线程,可以操作初始值为零的一个变量,
* 实现一个线程对该变量加1,一个线程对该变量减1,
* 实现交替,来10轮,变量初始值为零。
看代码:
package com.cxy.juc; class AirCondition{ private int num = 0; public synchronized void increment() throws Exception{ if(num !=0){ this.wait(); } num++; System.out.println(Thread.currentThread().getName()+"\t"+num); this.notifyAll(); } public synchronized void decrement() throws Exception{ if (num ==0){ this.wait(); } num--; System.out.println(Thread.currentThread().getName()+"\t"+num); this.notifyAll(); } } /** * 多线程操作: 线程操作资源类, * 判断,干活,通知 * 防止虚假唤醒 */ public class ProdConsumerDemo { public static void main(String[] args) throws Exception{ AirCondition airCondition =new AirCondition(); new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"a").start(); /*new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"c").start();*/ new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"b").start(); /* new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"d").start();*/ } }
执行结果是对的,
a 1 b 0 a 1 b 0 a 1 b 0 a 1 b 0 a 1 b 0 a 1
那么线程再增多呢,变成两个线程增加两个线程减少呢:
package com.cxy.juc; class AirCondition{ private int num = 0; public synchronized void increment() throws Exception{ if(num !=0){ this.wait(); } num++; System.out.println(Thread.currentThread().getName()+"\t"+num); this.notifyAll(); } public synchronized void decrement() throws Exception{ if (num ==0){ this.wait(); } num--; System.out.println(Thread.currentThread().getName()+"\t"+num); this.notifyAll(); } } /** * 多线程操作: 线程操作资源类, * 判断,干活,通知 * 防止虚假唤醒 */ public class ProdConsumerDemo { public static void main(String[] args) throws Exception{ AirCondition airCondition =new AirCondition(); new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"a").start(); new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"c").start(); new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"b").start(); new Thread(() ->{ for (int i = 0; i <10 ; i++) { try { airCondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"d").start(); } }
看结果:
b 0 c 1 d 0 a 1 d 0 c 1 b 0 d -1 d -2 a -1 b -2 b -3 a -2
那么出现bug了,而且是api级别的bug,怎么办呢,
多线程操作:高内聚低耦合,线程操作资源类,判断,干活,通知,防止虚假唤醒
那么在那个里面就需要在判断的时候,虚假唤醒了;
public final void wait() throws InterruptedException导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。 当前的线程必须拥有该对象的显示器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify方法或notifyAll方法notifyAll 。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。 像在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用: synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition } 该方法只能由作为该对象的监视器的所有者的线程调用。 有关线程可以成为监视器所有者的方式的说明,请参阅notify方法。 异常 IllegalMonitorStateException - 如果当前线程不是对象监视器的所有者。 InterruptedException - 如果任何线程在当前线程等待通知之前或当前线程中断当前线程。 当抛出此异常时,当前线程的中断状态将被清除。 另请参见: notify() , notifyAll()
所以需要将if判断变成while判断:
a 1 b 0 c 1 d 0 a 1 b 0 c 1 d 0 a 1 b 0 c 1 d 0 a 1 d 0 c 1 d 0
结果就对了