简单理解阻塞队列(BlockingQueue)中的take/put方法以及Condition存在的作用

Condition:可以理解成一把锁的一个钥匙,它既可以解锁(通知放行),又可以加锁(阻塞)

notFull:当队列元素满了时,阻塞生产,当队列元素存在元素但是没有满时,去通知消费

notEmpty:当队列中不存在元素时,阻塞消费,当队列元素存在元素时,去通知生产

while (count >= datas.length) {...}

while (count <= 0) {...}

两个while循环判断,而不用if,是因为线程不安全,

导致多线程场景下每个线程获取到的循环条件count的值存在差异,

导致代码执行异常,用while可以使当前线程重新刷新判断条件count的值。

用处:

ThreadPoolExecutor中使用到了阻塞队列,阻塞队列中又使用到了ReentrantLock,而ReentrantLock基于AQS。

package com.zhuyz.foundation.juc;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.ReentrantLock;

public class MyArrayBlockingQueue {

// 数组元素

private T[] datas;

// 实际的元素个数(也有索引下标的作用)

private volatile int count;

private final ReentrantLock putLock = new ReentrantLock();

private final ReentrantLock takeLock = new ReentrantLock();

// 通知消费,暂停生产【当数组full时await(put时),当数组notFull时signal(take时)】

private Condition notFull = putLock.newCondition();

// 通知生产,暂停消费【当数组empty时await(take时),当数组notEmpty时signal(put时)】

private Condition notEmpty = takeLock.newCondition();

public MyArrayBlockingQueue(int cap) {

this.datas = (T[]) new Object[cap];

}

private void put(T t) {

final ReentrantLock putLock = this.putLock;

putLock.lock();

try {

// 线程不安全,需要循环判断,插入值之前判断一下数组长度是否达到最大长度

while (count >= datas.length) {

System.out.println("datas is full, please waiting take");

notFull.await();

}

datas[count++] = t;

System.out.println("put: " + t);

} catch (Exception e) {

System.out.println("异常" + e);

} finally {

putLock.unlock();

}

// 通知获取元素的线程继续执行(take_thread)

final ReentrantLock takeLock = this.takeLock;

takeLock.lock();

try {

notEmpty.signal();

} finally {

takeLock.unlock();

}

}

private T take() {

final ReentrantLock takeLock = this.takeLock;

takeLock.lock();

T t = null;

try {

// 线程不安全,需要循环判断,插入值之前判断一下数组中元素个数是否为0

while (count <= 0) {

System.out.println("datas is empty, please waiting put");

notEmpty.await();

}

// 获取元素

t = datas[--count];

System.out.println("take: " + t);

} catch (Exception e) {

System.out.println("异常" + e);

} finally {

takeLock.unlock();

}

final ReentrantLock putLock = this.putLock;

putLock.lock();

try {

// 通知插入元素的线程继续执行(put_thread)

notFull.signal();

} finally {

putLock.unlock();

}

return t;

}

public static void main(String[] args) throws InterruptedException {

MyArrayBlockingQueue myArrayBlockingQueue = new MyArrayBlockingQueue<>(5);

for (int i = 0; i < 10; i++) {

int finalI = i;

new Thread(() -> myArrayBlockingQueue.put(finalI)).start();

}

TimeUnit.SECONDS.sleep(5L);

for (int i = 0; i < 5; i++) {

new Thread(() -> myArrayBlockingQueue.take()).start();

}

}

}

结果如下:

从结果中可以看出,先put了5个元素,然后另外五个元素被阻塞住了,没有进去

take消费5个之后,另外五个被阻塞的元素就被put进去了

put: 0

put: 1

put: 2

put: 3

put: 4

datas is full, please waiting take

datas is full, please waiting take

datas is full, please waiting take

datas is full, please waiting take

datas is full, please waiting take

take: 4

put: 5

take: 5

take: 3

put: 6

put: 7

take: 7

put: 8

take: 8

put: 9

本文地址:https://blog.csdn.net/qq_43128724/article/details/110438987

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

java阻塞队列作用_简单理解阻塞队列(BlockingQueue)中的take/put方法以及Condition存在的作用...相关推荐

  1. java url特殊字符处理_简单实例处理url特殊符号处理(2种方法)

    我遇到的问题是:url里的参数内容包含&符合,我有两种方法解决 其一方法是:在页面用JS转码,例子如下(前端处理) ${group.cn }) function test(a,b){ aler ...

  2. 面试问题-理解数字后仿,其次针对性理解数字后仿中的sdf文件(约束文件)的作用

    理解数字后仿,其次针对性理解数字后仿中的sdf文件(约束文件)的作用 1)什么是sdf文件 2)如何反标sdf文件? 1,什么是数字后仿? 2,什么是门级网表? 3,什么是sdf文件 4,如何反标sd ...

  3. 简单理解阻塞Io和非阻塞io

    https://www.kancloud.cn/lengyueguang/linux/1201612 有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但 ...

  4. finally在java程序中的作用_深入理解Java中的finally

    问题 在Java的异常体系中,我们经常会使用finally语句块来保证进行一些无论有无异常都要执行的处理流程,但finally语句块与return语句究竟哪个先执行总是让人迷惑.根据书本介绍,似乎是f ...

  5. java的弱引用_深入理解Java中的弱引用

    不久之前,我面试了一些求职Java高级开发工程师的应聘者.我常常会面试他们说,"你能给我介绍一些Java中得弱引用吗?",如果面试者这样说,"嗯,是不是垃圾回收有关的?& ...

  6. java注释和注解_深入理解JAVA注解(Annotation)以及自定义注解

    Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制.Java 语言中的类.方法.变量.参数和包等都可以被标注.注解可以看作是一种特殊的标记,在程序在编译或 ...

  7. Java:annotation注解的简单理解和总结

    Java annotation 注解Annotation 1.Annotation的概述 1.1.定义 1.2.Annotation作用分类 1.3.Annotation 架构 2.Annotatio ...

  8. java 内置锁_深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    synchronized 和 Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同 ...

  9. Java虚拟机不能满足_深入理解Java虚拟机--读书笔记1/3

    <深入理解Java虚拟机-JVM高级特性与最佳实践> Chap 2 Java内存区域与内存溢出异常 1.Java运行时数据区域 A.程序计数器:当前线程所执行字节码的行号指示器,线程私有( ...

最新文章

  1. [AaronYang]C#人爱学不学8[事件和.net4.5的弱事件深入浅出]
  2. android ui自动化测试工具,介绍Robotium+Orange实现androidUI自动化测试
  3. pointnet分割自己的点云数据_点云学习历史文章大汇总
  4. Centos下安装FTP并进行虚拟用户访问方式配置
  5. 合约实战,代币合约,DAPP开发
  6. 服务去获取配置中心配置
  7. 如何把网址配置为http和https可以同时访问
  8. 线下产品风控门道真不少
  9. 安装Jenkins后 启动时失败的问题解决
  10. field list什么意思_什么是生物信息学?
  11. (13)机器学习_LogisticRegression
  12. c++如何生成指定范围的随机数
  13. matlab开关占空比,高手指导 详解开关电源占空比选择与计算
  14. mescroll下拉刷新上拉加载
  15. 高数 | 极坐标下弧微元(线元ds)的推导
  16. opencv3.0 截取任意形状封闭图形
  17. 数据泵并行parallel参数问题
  18. 2021-09-08
  19. iOS应用跳转(包括iPhone原有应用跳转和第三方应用跳转)
  20. 解决Qt :libpng warning: iCCP: known incorrect sRGB profile警告信息

热门文章

  1. .netcore 极速接入第三方登录
  2. 使用Azure Functions玩转Serverless
  3. 基于.NetCore3.1系列 —— 日志记录之自定义日志组件
  4. IdentityServer 部署踩坑记
  5. GitHub 2019年度报告,用户超4000万
  6. 微软想将新版Edge浏览器引入Linux
  7. 利用ICSharpCore搭建基于.NET Core的机器学习和深度学习的本地开发环境
  8. NetCore服务虚拟化01(集群组件Sodao.Core.Grpc)
  9. .NET Core 3.0之创建基于Consul的Configuration扩展组件
  10. 现身说法:实际业务出发分析百亿数据量下的多表查询优化