3.生产者和消费者问题
感谢秦疆老师的JUC并发编程视频,更多了解哔哩哔哩搜索【狂神说Java】。
本文内容源于秦疆老师的JUC并发编程视频教程。给狂神推荐,点赞吧!
Synchronized版生产者和消费者的问题
package demo2;
/**
* 线程之间的通信问题: 生产者和消费者问题! 等待唤醒,通知唤醒
* 线程交替执行 A B 操作同一个变量 num = 0
* A num+1
* B num-1
*/
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
//等待 ,业务 ,通知
class Data {//数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
if (number != 0) { //0
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程 ,我+1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if (number == 0) { //1
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程 ,我-1完毕
this.notifyAll();
}
}
存在A B C D … 更多线程会出现问题 -->虚假唤醒
jdk1.8官方文档:
if 改为 while 判断
package demo2;
/**
* 线程之间的通信问题: 生产者和消费者问题! 等待唤醒,通知唤醒
* 线程交替执行 A B 操作同一个变量 num = 0
* A num+1
* B num-1
*/
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
//等待 ,业务 ,通知
class Data {//数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while (number != 0) { //0
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程 ,我+1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number == 0) { //1
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程 ,我-1完毕
this.notifyAll();
}
}
JUC版的生产者和消费者问题
通过Lock找到Condition
代码:
package demo2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程之间的通信问题: 生产者和消费者问题! 等待唤醒,通知唤醒
* 线程交替执行 A B 操作同一个变量 num = 0
* A num+1
* B num-1
*/
public class B {
public static void main(String[] args) {
DataB data = new DataB();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
//等待 ,业务 ,通知
class DataB {//数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// condition.await(); 等待
// condition.signalAll(); 唤醒全部
//+1
public void increment() throws InterruptedException {
lock.lock();
try {
while (number != 0) { //0
//等待
//this.wait();
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程 ,我+1完毕
// this.notifyAll();
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number == 0) { //1
//等待
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程 ,我-1完毕
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
输出结果:
A=>1
B=>0 //问题 随机的状态
A=>1 //有序执行 A - B - C - D
C=>0
A=>1
C=>0
A=>1
C=>0
A=>1
C=>0
A=>1
D=>0
A=>1
D=>0
A=>1
D=>0
A=>1
D=>0
A=>1
D=>0
任何一个新的技术,绝对不是仅仅只是覆盖了原来的技术,优势和补充!
Condition 精准的通知和唤醒线程
package demo2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* A - B - C
*/
public class C {
public static void main(String[] args) {
DataC data = new DataC();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.printC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
}
}
//等待 ,业务 ,通知
class DataC {//数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
// condition.await(); 等待
// condition.signal(); 唤醒
//执行A
public void printA() throws InterruptedException {
lock.lock();
try {
while (number != 0) { //0
//等待
conditionA.await();
}
number = 1;
System.out.println(Thread.currentThread().getName() + "=>" + number + "唤醒B");
//通知其他线程 ,我+1完毕
conditionB.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//执行B
public void printB() throws InterruptedException {
lock.lock();
try {
while (number != 1) { //0
//等待
//this.wait();
conditionB.await();
}
number = 2;
System.out.println(Thread.currentThread().getName() + "=>" + number + "唤醒C");
conditionC.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//执行C
public void printC() throws InterruptedException {
lock.lock();
try {
while (number != 2) { //0
//等待
conditionC.await();
}
number = 0;
System.out.println(Thread.currentThread().getName() + "=>" + number + "唤醒A");
conditionA.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
输出:
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A
A=>1唤醒B
B=>2唤醒C
C=>0唤醒A