JUC详解2——生产者消费者

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

生产者消费者

线程间的通信问题——生产者消费者问题
一个简单的生产者消费者模型(使用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锁问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值