生产者和消费者问题
生产者和消费者问题 Synchronized 版
/*** 线程之间的通信问题:生产者和消费者问题! 等待 通知唤醒* 线程交替执行 A B 操作同一个变量 num = 0* A num+1* B num-1*/public class A {public static void main(String[] args) {Data1 data = new Data1();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}}, "B").start();}}// 判断等待,业务,通知
class Data1 {private Integer num = 0;// +1 生产public synchronized void increment() {if (num != 0) {// 等待try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}num++;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程,我+1完毕了this.notifyAll();}// -1 消费public synchronized void decrement() {if (num == 0) {// 等待try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}num--;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程,我-1完毕了this.notifyAll();}}
问题存在,A B C D 4 个线程! 虚假唤醒
多线程环境的编程中,我们经常遇到让多个线程等待在一个条件上,等到这个条件成立的时候我们再去唤醒这些线程,让它们接着往下执行代码的场景。假如某一时刻条件成立,所有的线程都被唤醒了,然后去竞争锁,因为同一时刻只会有一个线程能拿到锁,其他的线程都会阻塞到锁上无法往下执行,等到成功争抢到锁的线程消费完条件,释放了锁,后面的线程继续运行,拿到锁时这个条件很可能已经不满足了,这个时候线程应该继续在这个条件上阻塞下去,而不应该继续执行,如果继续执行了,就说发生了虚假唤醒。
把if判断换成了while判断
public class A {public static void main(String[] args) {Data1 data = new Data1();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}}, "B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}}, "C").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}}, "D").start();}}// 判断等待,业务,通知
class Data1 {private Integer num = 0;// +1 生产public synchronized void increment() {while (num != 0) {// 等待try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}num++;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程,我+1完毕了this.notifyAll();}// -1 消费public synchronized void decrement() {while (num == 0) {// 等待try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}num--;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程,我-1完毕了this.notifyAll();}}
JUC版的生产者和消费者问题
public class B {public static void main(String[] args) {Data2 data = new Data2();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}}, "B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}}, "C").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}}, "D").start();}}// 判断等待,业务,通知
class Data2 {private Integer num = 0;private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();// +1 生产public void increment() {lock.lock();try {while (num != 0) {// 等待condition.await();}num++;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程,我+1完毕了condition.signalAll();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}// -1 消费public synchronized void decrement() {lock.lock();try {while (num == 0) {// 等待condition.await();}num--;System.out.println(Thread.currentThread().getName() + "=>" + num);// 通知其他线程,我-1完毕了condition.signalAll();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}}
Condition 精准的通知和唤醒线程
/*** A 执行完调用B,B执行完调用C,C执行完调用A*/
public class C {public static void main(String[] args) {Data3 data = new Data3();new Thread(() -> {for (int i = 0; i < 10; i++) {data.printA();}}, "A").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.printB();}}, "B").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.printC();}}, "C").start();}}// 判断等待,业务,通知
class Data3 {private Integer num = 1; // 1A 2B 3Cprivate Lock lock = new ReentrantLock();private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();public void printA() {lock.lock();try {while (num != 1) {// 等待condition1.await();}System.out.println(Thread.currentThread().getName() + " => AAAAAA");num = 2;// 唤醒,唤醒指定的人,Bcondition2.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}public void printB() {lock.lock();try {while (num != 2) {// 等待condition2.await();}System.out.println(Thread.currentThread().getName() + " => BBBBBB");num = 3;// 唤醒,唤醒指定的人,Ccondition3.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}public void printC() {lock.lock();try {while (num != 3) {// 等待condition3.await();}System.out.println(Thread.currentThread().getName() + " => CCCCCC");// 唤醒,唤醒指定的人,Anum = 1;condition1.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}}