Java阻塞队列

目录

一、阻塞队列的特点 

二、生产者,消费者

   存在问题:

三、阻塞队列,Java实现 

属性:

方法:

①put方法:"生产者"线程专门调用的方法。

 ②get方法:"消费者"线程专门调用的方法。

执行顺序分析:(图解)

在我们上图的代码当中,如果把while改成if,那么就会存在一个问题:wait()被唤醒之后,此时的if条件,一定不成立了吗?

 如图 :

四、JUC当中的阻塞队列      


一、阻塞队列的特点 

阻塞队列,也是一种先进先出的数据结构。和普通的队列(Queue)对比,它新增了两个功能:

       ①如果队列为空,执行出队列,按照Queue的规则,会抛出异常。但是在阻塞队列当中,会发生阻塞。直到有其他线程执行入队列的操作。


       ②如果队列满了,再执行入队列,那么执行入队列的线程会发生阻塞等待。直到有其他线程执行出队列的操作


二、生产者,消费者

    在并发编程当中,生产者就是生产数据的线程,消费者就是消费数据的线程。


   存在问题:

       如果生产数据的线程处理速度比较快,而消费数据的线程处理速度比较慢,那么生产者将会等待消费者消费完成之后,才能继续生产数据。

       反之,如果生产数据的线程生产比较慢,消费数据的线程消费数据比较快,那么消费数据的线程将需要等待生产数据的线程生产完毕之后,才可以继续消费。

        从以上的场景可以看出生产者和消费者之间的耦合度还是比较高的,因此,就引入了阻塞队列,来降低生产者和消费者之间的耦合度。


   解决问题——引入生产者消费者模式


生产者和消费者之间,是通过一个容器来解决生产者和消费者之间的强耦合问题。

由上图可以参考得出:生产者仅仅负责生产数据,消费者仅仅负责获取/消费数据,生产者和消费者之间并没有直接通信,而是通过一个阻塞队列之间通信。


生产者仅仅负责把数据生产完成之后放入到阻塞队列当中,消费者仅仅负责把数据取出来,然后供自己使用。

       也就是说,生产者把数据生产出来之后,直接把数据放到阻塞队列当中,无需等待消费者获取。

       消费者需要获取数据的时候,直接从阻塞队列当中获取,无需等待生产者生产数据,这就是生产者消费者模式


三、阻塞队列,Java实现 

属性:

     ①此处考虑需要使用一个数组来实现。

     ②需要定义一个头指针,一个尾指针。

     ③size属性记录队列当中的实际存储个数。


方法:

     ①put方法:"生产者"线程专门调用的方法。

     往阻塞队列当中存放元素。

     当队列满的时候,如果仍然有线程调用put方法,那么会进入WAITING状态。

     直到有"消费者"线程尝试从队列当中取出数据,然后把阻塞的"生产者“线程给唤醒。


 ②get方法:"消费者"线程专门调用的方法。

     取出阻塞队列当中的元素。

     当阻塞队列为空的时候,如果仍然有线程调用get方法,那么也会进入WAITING状态。

     直到有“生产者”线程尝试往线程当中存放数据,存放之后唤醒“消费者”线程。

 


执行顺序分析:(图解)


在我们上图的代码当中,如果把while改成if,那么就会存在一个问题:wait()被唤醒之后,此时的if条件,一定不成立了吗?


 如图 :

      在我们的代码当中,这里其实确实是被唤醒之后,if语句一定不成立了。if和while都可以。

      原因:在我们的代码设计当中,put()和get()方法都是同步方法,也就是:

      当队列为的时候,如果"生产者"想继续往队列当中存放元素,会因为条件size==elem.length满足而进入到if语句以内,调用wait()方法进入阻塞等待的状态。

      当被唤醒的时候,一定是要等“消费者”取出元素之后,由“消费者”来唤醒正在wait()的线程


       当队列为空的时候,同理。


       那么,可以理解为:在上面的代码(put方法)当中,"生产者"在被唤醒之前,已经由"消费者"取出了元素,破环了size==elem.length这个条件了,因此不需要再使用while循环的语句重复判断一次了。


       但是,看一下wait()方法的Object类的注释:

  

        因此,在使用形如:      

  synchronized(obj){

      if(条件)
          obj.wait()
       }

}

         这样的语句时候,应当改成:

  synchronized(obj){

       while(条件)
         obj.wait()
       }

}

       确保wait()被唤醒之前,已经满足了条件。


 

四、JUC当中的阻塞队列      

      常见的阻塞队列有:

   LinkedBlockingQueue,底层是一个链表实现的。
   ArrayBlockingQueue,底层是一个数组实现的。
   PriorityBlockingQueue,底层是一个优先级队列(堆)实现的。要求存放的元素不可以是空的,一定是可以比较的。

       代码实现(链表的阻塞队列)

     

    观察运行结果:

   

    可以看到,线程一直没有结束,一直阻塞。

     

   

     

  

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值