Java多线程操作同一份资源
现在两个线程,可以操作初始值为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,实现交替,来10轮,变量初始值为零。
package com.yangyuanyuan.juc1205; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Aircondition { private int number = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void increment()throws Exception { lock.lock(); try { //1 判断 while (number != 0) { condition.await();//this.wait(); } //2 干活 number++; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 condition.signalAll();//this.notifyAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void decrement()throws Exception { lock.lock(); try { //1 判断 while (number == 0) { condition.await();//this.wait(); } //2 干活 number--; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 condition.signalAll();//this.notifyAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } /*public synchronized void increment()throws Exception { //1 判断 while (number != 0) { //AAA CCC this.wait(); } //2 干活 number++; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 this.notifyAll(); } public synchronized void decrement()throws Exception { //1 判断 while(number == 0) { this.wait(); } //2 干活 number--; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 this.notifyAll(); }*/ } /** 1 高聚低合前提下,线程操作资源类 2 判断/干活/通知 3 防止虚假唤醒 不能使用if判断,会出现2 知识小总结 = 多线程编程套路+while判断+新版写法 */ public class ProdConsumerDemo04 { public static void main(String[] args)throws Exception { Aircondition aircondition = new Aircondition(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(200); aircondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"A").start(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(300); aircondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"B").start(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(400); aircondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"C").start(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(500); aircondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"D").start(); } }
使用if判断存在虚假唤醒情况,变量可能会变成2
如图所示,如果只有两个线程,一个线程加,一个线程减,不会存在虚假唤醒情况(选无可选)。
当变成四个线程时,两个线程加,两个线程减,使用if就会存在虚假唤醒情况。如变量初始为0(0!=0为false),执行完+’变量变成1,此时+线程进来发现值为1等待(this.wait()处等待,未出if判断),然后+‘线程又进来发现值为1它也等待(this.wait()处等待,未出if判断),此时-线程进来(1==0为false)发现变量值为1将变量做减法变成0。由于此时+和+‘仍在等待,cpu为了降低消耗量和负担,会先满足等待时间长的线程(线程优先级会高)
由于使用的是if,不会再拉回来重新判断一次(两个线程this.wait()处等待),+和+’线程都会做加法,变量值就变成了2。