Lock实现生产者消费者问题

  什么是生产者消费者问题?

所谓的生产者消费者问题,是通过一个容器来解决生产者和消费者的强耦合问题。通俗的讲,就是生产者在不断的生产,消费者也在不断的消费,可是消费者消费的产品是生产者生产的,这就必然存在一个中间容器,我们可以把这个容器想象成是一个货架,当货架空的时候,生产者要生产产品,此时消费者在等待生产者往货架上生产产品,而当货架满的时候,消费者可以从货架上拿走商品,生产者此时等待货架的空位,这样不断的循环。那么在这个过程中,生产者和消费者是不直接接触的,所谓的‘货架’其实就是一个阻塞队列,生产者生产的产品不直接给消费者消费,而是仍给阻塞队列,这个阻塞队列就是来解决生产者消费者的强耦合的。就是生产者消费者问题。

那生产者消费者问题有什么用?

  • 生产与消费的速度不匹配
  • 软件开发过程中解耦

这篇文章通过JUC中的Lock接口来实现生产者消费者问题;
首先,我们得知道知道几个知识点:

Lock

lock锁是JDK1.5之后推出的一种锁机制,可以通过使用ReentrantLock实现类来实现实现线程之间的同步互斥,且在使用上比synchronized更加灵活。

查看JDK帮助文档,我们得知Lock锁的简单使用:
在这里插入图片描述

Condition

回忆 synchronized 关键字,它配合 Object 的 wait()、notify() 系列方法可以实现等待/通知模式。对于 Lock,通过 Condition 也可以实现等待/通知模式。Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。

查看JDK帮助文档,我们知道这个接口的实现类和使用方法:

在这里插入图片描述
当我们了解完上面几个知识点,这时候我们就可以去写一个生产者消费者问题例子:

/**
 * 通过Lock锁来实现生产者和消费者问题
 */
public class ProducerAndConsumer2 {

    public static void main(String[] args) {
        ProAndCon2 proAndCon2 = new ProAndCon2();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                    proAndCon2.Pro();
            }
        },"A").start();

        new Thread(()->{ //让B线程去执行消费者方法
            for (int i = 0; i < 5; i++) {
                    proAndCon2.Con();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                    proAndCon2.Pro();
            }
        },"C").start();

        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                    proAndCon2.Con();
            }
        },"D").start();
    }
}

/**
 * 在 Lock取代 synchronized方法和语句的使用,一个 Condition取代对象监视器的使用方法。
 */
class ProAndCon2{
    private int num=0; //创建一个公共变量

    //创建可重入锁对象
    Lock lock=new ReentrantLock();  //可以取代synchronized

    //创建Condition对象(用于监听)
   Condition condition=lock.newCondition();//取代对象监视器的使用方法。 例如wait notifyAll等等

    //生产者方法
    public void Pro(){
   //开启锁
        lock.lock();
        try {
            while (num !=0){
                condition.await();//等待
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"->"+num);
            condition.signalAll();//唤醒所有线程
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    //消费者方法
    public  void Con(){
        //开启锁
        lock.lock();
        try {
            while (num==0){
              condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"->"+num);
            condition.signalAll();//唤醒所有线程
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

结果如下:
在这里插入图片描述

这时候我们发现虽然可以去实现生产者消费者问题,但是我们想精准的唤醒执行,例如:A执行---->B执行---->C执行---->A执行---->B执行---->C…

我们依然可以通过Condition实现....

创建一个例子,依然通过Lock和Condition来实现:

通过Lock锁和Condition对象去实现一个生产者消费者问题的升级
A 唤醒->B 唤醒-> C 唤醒 ->A
 */
public class ProducerAndConsumer3 {
    public static void main(String[] args) {
        ProAndCon3 proAndCon3 = new ProAndCon3();
        new Thread(()->{
            for (int i = 0; i <5 ; i++) {
                proAndCon3.printA();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i <5 ; i++) {
                proAndCon3.printB();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i <5 ; i++) {
                proAndCon3.printC();
            }
        },"C").start();

    }
}
 class ProAndCon3{
    //创建Lock锁对象
    Lock lock=new ReentrantLock();
    //创建Condition对象
     Condition condition1=lock.newCondition();
     Condition condition2=lock.newCondition();
     Condition condition3=lock.newCondition();

     private  int num=1;
     //创建一个A执行方法
    public void printA(){
       lock.lock();
        try {
            while (num!=1){
                //让condition1绑定到执行这个方法的线程上
                condition1.await();//当num不等于1的时候,等待
            }
            System.out.println(Thread.currentThread().getName()+"->执行AAAAAAAAAAAAAAAAAAAAAAAAAA");
            num=2;
            condition2.signal();//唤醒绑定的线程2的condition对象
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
     //创建一个B执行方法
     public void printB(){
         lock.lock();
         try {
             while (num!=2){
                 //让condition1绑定到执行这个方法的线程上
                 condition2.await();//当num不等于1的时候,等待
             }
             System.out.println(Thread.currentThread().getName()+"->执行BBBBBBBBBBBBBB");
             num=3;
             condition3.signal();//唤醒绑定的线程2的condition对象
         } catch (InterruptedException e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }
     //创建一个C执行方法
     public void printC(){
         lock.lock();
         try {
             while (num!=3){
                 //让condition1绑定到执行这个方法的线程上
                 condition3.await();//当num不等于1的时候,等待
             }
             System.out.println(Thread.currentThread().getName()+"->执行CCCCCCCCCCCCCCCCCCCCCCCCCC");
             num=1;
             condition1.signal();//唤醒绑定的线程2的condition对象
         } catch (InterruptedException e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }
}

结果如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨某人的快乐学习日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值