对于两个线程a,b;
首先线程a:
(1) 判断:变量值如果为0
(2) 干活:变量值+1
(3) 通知:a线程通知b线程对变量-1
其次线程b:
(1) 判断:变量值如果为1
(2) 干活:变量值-1
(3) 通知:b线程通知a线程对变量+1
依次类推。。。
package JUC.sync; //第一步 创建资源类,定义属性和操作方法 class Share { //初始值 private int number = 0; //+1的方法 public synchronized void incr() throws InterruptedException { //第二步 判断 干活 通知 if (number != 0) { //判断number值是否为0,如果不是0,等待 this.wait(); } //如果number值是0,就+1操作 number++; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知其他线程 this.notifyAll(); } //-1的方法 public synchronized void decr() throws InterruptedException { //第二步 判断 干活 通知 if (number != 1) { //判断number值是否为1,如果不是1,等待 this.wait(); } //如果number值是1,就-1操作 number--; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知其他线程 this.notifyAll(); } } public class ThreadDemo1 { //第三步 创建多个线程,调用资源类的操作方法 public static void main(String[] args) { Share share = new Share(); //创建线程 new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.incr();//+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { share.decr();//-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); } }
如果线程为4个,会出现 虚假唤醒 的问题
解决方案:
判断语句由 if 改为 while。while条件不管wait什么时候睡,什么时候醒,都要经过判断条件。
package JUC.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //第一步 创建资源类,定义属性和操作方法 class Share { private int number = 0; //创建Lock final Lock lock = new ReentrantLock(); final Condition condition = lock.newCondition(); //+1 public void incr() throws InterruptedException { //上锁 lock.lock(); try{ //判断 while(number != 0){ condition.await(); } //干活 number++; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知 condition.signalAll(); } finally { //解锁 lock.unlock(); } } //-1 public void decr() throws InterruptedException { //上锁 lock.lock(); try{ //判断 while(number != 1){ condition.await(); } //干活 number--; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知 condition.signalAll(); } finally { //解锁 lock.unlock(); } } } public class ThreadDemo2 { public static void main(String[] args) { Share share = new Share(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"DD").start(); } }
方案:给每个线程定义一个标志位。
package JUC.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //第一步 创建资源类,定义属性和操作方法 class ShareResource { //定义标志位 private int flag = 1;// 1 AA 2 BB 3 CC //创建Lock锁 final Lock lock = new ReentrantLock(); //创建三个condition final Condition c1 = lock.newCondition(); final Condition c2 = lock.newCondition(); final Condition c3 = lock.newCondition(); //打印5次,参数第几轮 public void print5(int loop) throws InterruptedException { //上锁 lock.lock(); try{ //判断 while(flag != 1){ c1.await(); } //干活 for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName()+" :: "+i+" :轮数: "+loop); } //修改标志位 flag = 2; //通知 c2.signalAll(); } finally { //解锁 lock.unlock(); } } //打印10次,参数第几轮 public void print10(int loop) throws InterruptedException { //上锁 lock.lock(); try{ //判断 while(flag != 2){ c2.await(); } //干活 for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName()+" :: "+i+" :轮数: "+loop); } //修改标志位 flag = 3; //通知 c3.signalAll(); } finally { //解锁 lock.unlock(); } } //打印15次,参数第几轮 public void print15(int loop) throws InterruptedException { //上锁 lock.lock(); try{ //判断 while(flag != 3){ c3.await(); } //干活 for (int i = 1; i <= 15; i++) { System.out.println(Thread.currentThread().getName()+" :: "+i+" :轮数: "+loop); } //修改标志位 flag = 1; //通知 c1.signalAll(); } finally { //解锁 lock.unlock(); } } } public class ThreadDemo3 { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { shareResource.print5(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { shareResource.print10(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { shareResource.print15(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); } }