传统线程生产者-消费者模式
传统线程生产者-消费者模式
大厂面试题:
我们都知道ArrayList是线程不安全的,请编码写一个不安全的案例并给出解决方案?
公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁。
CountDownLatch、CyclicBarrier、Semaphore使用过吗?
阻塞队列知道吗?
线程池用过吗?ThreadPoolExecutor谈谈你的理解?
线程池用过吗?生产上你是如何设置合理参数?
死锁编码及定位分析?
1、传统线程生产者-消费者模式是什么?
2、传统生产者-消费者模式代码验证2.0版本
Demo One:判断使用while不会出现虚假唤醒问题
package com.wwl.juc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程操作的共享资源类
*/
class ShareData {
private int 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() + "\t" + num);
// 生产者线程通知唤醒消费者线程
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// 减法操作-1
public void decrement() {
lock.lock();
try {
while (num == 0) {
// 消费者线程等待消费
condition.await();
}
// 消费者线程进行消费操作
num--;
System.out.println(Thread.currentThread().getName() + "\t" + num);
// 消费者线程通知唤醒生产线程
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* 面试题目:一个初始值为0的变量,两个线程对其交替操作,一个加1,一个减1,交替循环5次
* 传统模式的生产者和消费者Demo
* 1、线程操作资源共享类ShareData
* 2、线程判断(while)是否执行加减操作
* 3、线程操作完成之后,需要通知(condition.signalAll())其他线程
* 4、防止虚假唤醒机制(if和while使用哪个?当然是使用while来判断)
*/
public class ProducerAndConsumerDemo {
public static void main(String[] args) {
ShareData shareData = new ShareData();
// 线程t1进行加法操作
new Thread(() -> {
for (int i = 0; i < 5; i++) {
shareData.increment();
}
}, "t1").start();
// 线程t2进行减法操作
new Thread(() -> {
for (int i = 0; i < 5; i++) {
shareData.decrement();
}
}, "t2").start();
}
}
程序执行结果如下:生产者线程和消费者线程交替执行加减操作
Demo Two:判断使用if操作会出现虚假唤醒问题(模拟生产者和消费者线程数要大于2,我这里使用两个生产者线程和两个消费这线程)
package com.wwl.juc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程操作的共享资源类
*/
class ShareData {
private int num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
// 加法操作+1
public void increment() {
lock.lock();
try {
if (num != 0) {
// 生产者线程等待生产
condition.await();
}
// 生产者线程进行生产操作
num++;
System.out.println(Thread.currentThread().getName() + "\t" + num);
// 生产者线程通知唤醒消费者线程
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// 减法操作-1
public void decrement() {
lock.lock();
try {
if (num == 0) {
// 消费者线程等待消费
condition.await();
}
// 消费者线程进行消费操作
num--;
System.out.println(Thread.currentThread().getName() + "\t" + num);
// 消费者线程通知唤醒生产线程
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* 面试题目:一个初始值为0的变量,两个线程对其交替操作,一个加1,一个减1,交替循环5次
* 传统模式的生产者和消费者Demo
* 1、线程操作资源共享类ShareData
* 2、线程判断(while)是否执行加减操作
* 3、线程操作完成之后,需要通知(condition.signalAll())其他线程
* 4、防止虚假唤醒机制(if和while使用哪个?当然是使用while来判断)
*/
public class ProducerAndConsumerDemo {
public static void main(String[] args) {
ShareData shareData = new ShareData();
// 线程t1进行加法操作
new Thread(() -> {
for (int i = 0; i < 5; i++) {
shareData.increment();
}
}, "t1").start();
// 线程t2进行减法操作
new Thread(() -> {
for (int i = 0; i < 5; i++) {
shareData.decrement();
}
}, "t2").start();
// 线程t3进行加法操作
new Thread(() -> {
for (int i = 0; i < 5; i++) {
shareData.increment();
}
}, "t3").start();
// 线程t4进行减法操作
new Thread(() -> {
for (int i = 0; i < 5; i++) {
shareData.decrement();
}
}, "t4").start();
}
}
程序执行结果如下:生产者线程和消费者线程没有交替执行加减操作