Condition对象

一)、Condition的定义

Condition对象:与锁关联,协调多线程间的复杂协作。

获取与锁绑定的Condition对象:

Lock lock = new ReentrantLock();

Conndition condition = lock.newConndition();

Condition的方法:

await(): 使当前的线程等待并释放锁。

singalAll(): 唤醒所有等待的线程,只有一个线程重新获得锁,并执行。

awaitterruptibly(): 使当前线程等待并释放锁,但在等待过程中不响应中断。

singal(): 唤醒一个正在等待的线程。

注:当线程处于中断状态也能跳出等待。

Condition对象与锁的关系

相当于object.wait(),Object.notify()与Synchronized一样,配合使用,以完成多线程协作的控制。

Lock lock = new ReentrantLock();
Conndition condition = lock.newCondition();
//线程进入等待状态
condition.await();
//唤醒等待的线程
condition.notify();

二)、ArrayBlockingQueue: 使用Condition实现队列的阻塞

(2-1):ArrayBlockQueue的主要属性

 //存放元素的数组,当元素个数超过数组的长度,调用的线程进入阻塞状态
final Object[] items;
//取出元素的数组下标
int takeIndex;
//添加元素的下标
int putIndex;
//数组中元素的个数
int count;
//公共锁对象
final ReentrantLock lock;
//与锁相对应的Condition(锁的监视器)
//等待队列不为空的时候
private final Condition notEmpty;
//等待队列不为满的时候
private final Condition notFull;

(2-2):构造方法

    public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
//创建公共锁对象,final修饰,对象一创建不能修改,final修饰的变量不能改变他的引用地址,但是可以改变它的值。
lock = new ReentrantLock(fair);
//与锁相关联的Condition
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}

(2-3):ArrayBlockingQueue的主要方法:

1). put(E e): 添加元素到队列

特点:

1).当队列的元素满时,阻塞当前的线程。

​ noFull.await() : 等待队列不满的时候。

2).添加一个元素后,唤醒一个消费线程。

​ noEmpty.singnal(): 队列不空,发出信号,唤醒等待不为空的线程

    public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
//等待队列不为满的时候
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
} //入队
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
//唤醒等待不为空的线程
notEmpty.signal();
}

2). take(): 获取队列中的元素

特点:

1).当队列为空时,阻塞当前调用线程。

​ noEmpty.await: 等待队列非空的时候

2).获取一个元素,唤醒一个生产线程。

​ noFull.singnal(): 唤醒一个等待队列不为满的线程

    public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
//线程进入等待状态,等待队列非空
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
} //出列
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
//唤醒一个等待队列不为满时的线
notFull.signal();
return x;
}

(2-4):队列先进先出的控制

putIndex: 0 - item.length, count++

if (++putIndex == items.length)
putIndex = 0;
count++;

takeIndex:0 - item.length,count--

if (++takeIndex == items.length)
//控制着元素的先进先出
takeIndex = 0;
count--;

总结: 元素从0开始写入,从0开始读取,由count控制着元素的读取,当putIndex =

​ item.length时,只要count不等于item.length,那么item[0]的元素必定被消

​ 费,当takeIndex = item.length时,只要count不等于0,item[0]必有元素存

​ 在。

count: 0 - item.length,控制着是否读取元素或写入元素

三)、使用ArrayBlockingQueue来构建生产者 - 消费者模式

生产者:Producer

/**
* 生产者进程
*
* 生产者 - 消费者模式
* 共同维护一个存储队列
* 队列特点:
* 队列满时,阻塞生产者,线程进入等待状态。
* 队列为空时,阻塞消费者,线程进入等待状态。
*/
public class Producer extends Thread {
/**
* 生产者维护的生产队列,指明队列存储元素的大小
*/
protected ArrayBlockingQueue queue; public Producer(ArrayBlockingQueue queue,String name) {
super(name);
this.queue = queue;
} /**
* 生产者生产线程
*/
@Override
public void run() {
try {
Thread.sleep(100);
Object obj = new Object();
System.out.println(Thread.currentThread().getName()+" 正在生产");
//模拟生产者的生产过程
queue.put(obj);
System.out.println(Thread.currentThread().getName()+" 生产了一件商品。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
} }

消费者:Consumer

/**
* 消费者线程,维护了一个消费队列
*/
public class Consumer extends Thread{
protected ArrayBlockingQueue queue; public Consumer(ArrayBlockingQueue queue,String name) {
super(name);
this.queue = queue;
} @Override
public void run() {
//模拟消费者线程进行消费
try {
System.out.println(Thread.currentThread().getName()+" 要开始消费了");
queue.take();
System.out.println(Thread.currentThread().getName()+" 消费了一件商品");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

启动线程:Client

/**
* 开启多个线程进行生产,开启多个线程进行消费
*/ public class Client {
public static void main(String[] args) {
ArrayBlockingQueue queue = new ArrayBlockingQueue(20);
ExecutorService executor = Executors.newFixedThreadPool(200);
Producer producer1 = new Producer(queue,"producer - 1");
Producer producer2 = new Producer(queue,"producer - 2");
Producer producer3 = new Producer(queue,"producer - 3");
Consumer consumer1 = new Consumer(queue,"consumer - 1");
Consumer consumer2 = new Consumer(queue,"consumer - 2");
Consumer consumer3 = new Consumer(queue,"consumer - 3");
//开启多个线程进行生产
executor.execute(producer1);
executor.execute(producer2);
executor.execute(producer3); //开启多个线程进行消费
executor.execute(consumer1);
executor.execute(consumer2);
executor.execute(consumer3); }
}

结果:

pool-1-thread-5 要开始消费了
pool-1-thread-4 要开始消费了
pool-1-thread-6 要开始消费了
pool-1-thread-1 正在生产
pool-1-thread-1 生产了一件商品。。。
pool-1-thread-2 正在生产
pool-1-thread-3 正在生产
pool-1-thread-5 消费了一件商品
pool-1-thread-6 消费了一件商品
pool-1-thread-4 消费了一件商品
pool-1-thread-2 生产了一件商品。。。
pool-1-thread-3 生产了一件商品。。。

结果分析:

消费者消费ArrayBlockingQueue的数据时,当队列为空的时候会阻塞当前的线程,当生产者生产了一件商品后会唤醒一个阻塞的线程。

练习代码github地址:https://github.com/slob-cow/java_performance_optimization/tree/master/Condition

Condition对象以及ArrayBlockingQueue阻塞队列的实现(使用Condition在队满时让生产者线程等待, 在队空时让消费者线程等待)的更多相关文章

  1. ArrayBlockingQueue 阻塞队列和 Semaphore 信号灯的应用

    import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public cl ...

  2. ArrayBlockingQueue 阻塞队列 生产者 与消费者案例

    package com.originalityTest; import java.net.UnknownHostException; import java.util.ArrayList; impor ...

  3. java多线程8:阻塞队列与Fork/Join框架

    队列(Queue),是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的. BlockingQueue 而阻塞队列BlockingQueue除了继承 ...

  4. 10.并发包阻塞队列之ArrayBlockingQueue

    上一节中对并发包中的非阻塞队列ConcurrentLinkedQueue的入队.出队做了一个简要的分析,本文将对并发包中的阻塞队列做一个简要分析. Java并发包中的阻塞队列一共7个,当然他们都是线程 ...

  5. 并发包阻塞队列之ArrayBlockingQueue

    并发包阻塞队列之ArrayBlockingQueue   jdk1.7.0_79  上一节中对并发包中的非阻塞队列ConcurrentLinkedQueue的入队.出队做了一个简要的分析,本文将对并发 ...

  6. 阻塞队列BlockingQueue之ArrayBlockingQueue

    ArrayBlockingQueue  是数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序. 构造方法: public ArrayBlockingQueue(int capa ...

  7. Java中的阻塞队列

    1. 什么是阻塞队列? 阻塞队列(BlockingQueue)是一个支持两个附加操作的队列.这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空.当队列满时,存储元素的线程会等待队列可用 ...

  8. Java并发编程之阻塞队列

    1.什么是阻塞队列? 队列是一种数据结构,它有两个基本操作:在队列尾部加入一个元素,从队列头部移除一个元素.阻塞队里与普通的队列的区别在于,普通队列不会对当前线程产生阻塞,在面对类似消费者-生产者模型 ...

  9. 聊聊并发(七)——Java中的阻塞队列

    3. 阻塞队列的实现原理 聊聊并发(七)--Java中的阻塞队列 作者 方腾飞 发布于 2013年12月18日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办,了解更 ...

随机推荐

  1. vmware14安装centos7的步骤(图文详解)

    一.centos的安装 centos分为桌面版和黑屏版(命令行版):在这里我使用的是命令行版. 这里选择安装程序光盘映像文件,文件就是centos7的iso文件. 虚拟机的名称和位置自行设置; 虚拟机 ...

  2. 玩转OneNET物联网平台之简介

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  3. 玩转u8g2 OLED库 MAX7219_32X8点阵模块

    u8g2 OLED库 + MAX7219_32X8点阵模块 理论基础 玩转u8g2 OLED库,一篇就够 玩转u8g2 OLED库,一篇就够(字数太多 要分篇) 实验内容 Full screen bu ...

  4. Java properties | FileNotFoundException: properties (系统找不到指定的文件。)

    文件存储路径的问题 错误描述 :FileNotFoundException: init.properties (系统找不到指定的文件.) 1.方法一 InputStream fis =TestProp ...

  5. unity UI事件

    由于工作需要到持续按键,所以了解了一下unity UI事件,本文主要转载于http://www.cnblogs.com/zou90512/p/3995932.html?utm_source=tuico ...

  6. leetcode系列---3Sum C#code

    Function: public static List<int[]> SumSet(int[] array) { List<int[]> result = new List& ...

  7. ThinkCMF X1.6.0-X2.2.3框架任意内容包含漏洞分析复现

    ThinkCMF X1.6.0-X2.2.3框架任意内容包含漏洞分析复现 一.ThinkCMF简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理系统框架,底层采用ThinkPHP3. ...

  8. UE4蓝图与C++交互——射击游戏中多武器系统的实现

    回顾   学习UE4已有近2周的时间,跟着数天学院"UE4游戏开发"课程的学习,已经完成了UE4蓝图方面比较基础性的学习.通过UE4蓝图的开发,我实现了类似CS的单人版射击游戏,效 ...

  9. 程序员接私活经验总结,来自csdn论坛语录

    以下为网上摘录,以做笔记: 可是到网上看看,似乎接私活也有很多不容易,技术问题本身是个因素,还有很多有技术的人接私活时被骗,或者是合作到最后以失败告终,所以想请有经验的大侠们出来指点一下,接私活是怎么 ...

  10. Java学习总结之基本数据类型

    Java的数据类型分为基本数据类型和引用数据类型, 今天总结的是基本数据类型.在Java中,一共有八种基本数据类型,分别为整数类型(byte,short,int,long).浮点类型(float,do ...