JUC-生产者消费者问题-02
生产者消费者问题
面试的:单例模式,排序算法,生产者消费者问题,死锁
- sychronized版本
package com.rongrong.pc;
/**
线程之间通信问题,生产者消费者问题,等待唤醒,通知唤醒
线程之间交替进行,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 num = 0;
public synchronized void increment() throws InterruptedException {
if (num != 0) {
//等待
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+num);
//通知其他线程,我加完了
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (num == 0) {
//等待
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+num);
//通知其他线程,我减完了
this.notifyAll();
}
}
问题存在:A,B,C,D四个线程,虚假唤醒
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0qk2pWOy-1604313796701)(/Users/chenxiwen/Library/Application Support/typora-user-images/image-20201102162033622.png)]
if改为while判断
最大的不同点是:IF语句运行完毕后,接着运行下面的语句。而While中的执行语句运行完毕后,还要进行继续判断条件是否符合循环条件,根据判断的条件,返回执行语句或继续运行下面的程序。
如果用if判断,多个等待线程在满足if条件时都会被唤醒(虚假的),但实际上条件并不满足,生产者生产出来的消费品已经被第一个线程消费了。
这就是我们使用while去做判断而不是使用if的原因:因为等待在条件变量上的线程被唤醒有可能不是因为条件满足而是由于虚假唤醒。所以,我们需要对条件变量的状态进行不断检查直到其满足条件,不仅要在pthread_cond_wait前检查条件是否成立,在pthread_cond_wait之后也要检查。
- Lock版本(JUC)
通过Lock找到Condition
package com.rongrong.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class B {
public static void main(String[] args) {
Data2 data = new Data2();
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.increment();
} 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 Data2{//数字,资源类
private int num = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
while (num != 0) {
//等待
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName()+num);
//通知其他线程,我加完了
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while (num == 0) {
//等待
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+num);
//通知其他线程,我减完了
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition 精准地通知和唤醒线程,有序执行ABCD
代码测试
package com.rongrong.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
A执行完执行B,B执行完执行C,C执行网执行A
*/
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data3.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data3.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data3.printC();
}
},"C").start();
}
}
class Data3 {//资源类 lock
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
private int number = 1;
public void printA() {
lock.lock();
try {
//判断等待,执行,通知
while (number != 1) {
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"A");
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
//判断等待,执行,通知
while (number != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"B");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
//判断等待,执行,通知
while (number != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"C");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}