生产者消费者
线程间的通信问题——生产者消费者问题
一个简单的生产者消费者模型(使用synchronized)
使用synchronized方法解决
package com.fly.juc.pc;
/**
* @Description 生产者、消费者
* 线程间通信问题————生产者、消费者问题:等待唤醒;通知唤醒
* 线程交替执行:P:生产者、C:消费者, 操作同一个变量
* P:+1
* C:-1
* @ClassName ProCon
* @Author cai feifei
* @date 2020.10.23 20:56
* @Version
*/
public class ProCon {
public static void main(String[] args) {
PC pc = new PC();
new Thread(()->{
for (int i=0;i<10;i++){
try {
pc.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"P").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
pc.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
}
}
class PC{
private int number = 0;
public synchronized void increment() throws InterruptedException {
if (number!=0){
//等待
this.wait();
}
//业务
number++;
System.out.println(Thread.currentThread().getName()+"===="+number);
//通知
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (number==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"===="+number);
this.notifyAll();
}
}
整齐的输出:

当存在多个生产者和消费者的时候

源码中的说明

这种线程的虚假唤醒,可以使用while来做判断等待
class PC{
private int number = 0;
public synchronized void increment() throws InterruptedException {
while (number!=0){
//等待
this.wait();
}
//业务
number++;
System.out.println(Thread.currentThread().getName()+"===="+number);
//通知
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (number==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"===="+number);
this.notifyAll();
}
}
使用lock解决生产者消费者问题
package com.fly.juc.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description 生产者、消费者
* 线程间通信问题————生产者、消费者问题:等待唤醒;通知唤醒
* 线程交替执行:P:生产者、C:消费者, 操作同一个变量
* P:+1
* C:-1
* @ClassName ProCon
* @Author cai feifei
* @date 2020.10.23 20:56
* @Version
*/
public class ProConJuc {
public static void main(String[] args) {
PCJ pc = new PCJ();
new Thread(()->{
for (int i=0;i<10;i++){
try {
pc.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"P1").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
pc.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C1").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
pc.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"P2").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
pc.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C2").start();
}
}
class PCJ {
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
while (number != 0) {
//等待
condition.await();
}
//业务
number++;
System.out.println(Thread.currentThread().getName() + "====" + number);
//通知
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number != 0) {
//等待
condition.await();
}
//业务
number--;
System.out.println(Thread.currentThread().getName() + "====" + number);
//通知
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

生产者和消费者随机执行,
如何精准唤醒和通知线程,从而按照自己的意愿进行执行
Condition:同步监视器
使用Condition实现指定唤醒功能
package com.fly.juc.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description 一把锁实现流水线
* @ClassName ProConJuc
* @Author cai feifei
* @date 2020.10.23 20:56
* @Version
*/
public class ProConJuc {
public static void main(String[] args) {
PCJ pc = new PCJ();
new Thread(()->{for (int i=0;i<10;i++){pc.partA();}},"A").start();
new Thread(()->{for (int i=0;i<10;i++){pc.partB();}},"B").start();
new Thread(()->{for (int i=0;i<10;i++){pc.partC();}},"C").start();
}
}
class PCJ {
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void partA(){
lock.lock();
try {
//业务:判断等待-》执行-》通知
while (number!=0){
condition1.await();
}
//业务
System.out.println(Thread.currentThread().getName()+"线程执行了========"+number);
//唤醒,指定唤醒:condition2=>B
number=1;
condition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void partB(){
lock.lock();
try {
//业务:判断等待-》执行-》通知
while (number!=1){
condition2.await();
}
//业务
System.out.println(Thread.currentThread().getName()+"线程执行了========"+number);
//唤醒,指定唤醒:condition3=>C
number=2;
condition3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void partC(){
lock.lock();
try {
//业务:判断等待-》执行-》通知
while (number!=2){
condition3.await();
}
//业务
System.out.println(Thread.currentThread().getName()+"线程执行了========"+number);
//唤醒,指定唤醒:condition1=>A
number=0;
condition1.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
程序有序依次执行

高频面试题:一个主线程三个子线程,如何让三个子线程执行结束再执行主线程
package com.fly.juc.pc;
/**
* @Description 一个主线程三个子线程,如何让三个子线程执行结束再执行主线程
* @ClassName JoinTest
* @Author cai feifei
* @date 2020.10.24 08:50
* @Version
*/
public class JoinTest {
public static void main(String[] args) {
Data data = new Data();
try {
Thread thread1 = new Thread(()->{data.test();},"A");
Thread thread2 = new Thread(()->{data.test();},"B");
Thread thread3 = new Thread(()->{data.test();},"C");
thread1.start();
thread2.start();
thread3.start();
//让三个线程执行完,如果在调用start方法后面直接调用join方法,那么三个线程将串行
thread1.join();
thread2.join();
thread3.join();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("主线程执行");
}
}
class Data{
public void test(){
System.out.println(Thread.currentThread().getName()+"线程执行了");
}
}
上一篇:JUC详解1
下一篇:JUC详解3——8锁问题

本文详细探讨了生产者消费者问题的两种解决方案,分别是使用synchronized关键字和ReentrantLock配合Condition。通过实例展示了如何确保线程按顺序执行,并处理多线程下的并发控制。面试高频题部分讲解了如何在一个主线程和三个子线程中同步执行。
365

被折叠的 条评论
为什么被折叠?



