一个锁可能关联了一个或多个条件。这些条件可以在Condition接口中声名。



使用这些条件的目的是去控制一个锁并且可以检查一个条件是true或false,如果为false,则暂停直到

另一个线程来唤醒它。



Condition接口提供了这样一个机制 去暂定一个线程和唤醒一个暂停中的线程。

本例中继续拿生产者-消费者问题举例。

FileMock.java
package com.dylan.thread.ch2.c07.utils;

/**
* This class simulates a text file. It creates a defined number
* of random lines to process them sequentially.
*
*/
public class FileMock { /**
* Content of the simulate file
*/
private String content[];
/**
* Number of the line we are processing
*/
private int index; /**
* Constructor of the class. Generate the random data of the file
* @param size: Number of lines in the simulate file
* @param length: Length of the lines
*/
public FileMock(int size, int length){
content=new String[size];
for (int i=0; i<size; i++){
StringBuilder buffer=new StringBuilder(length);
for (int j=0; j<length; j++){
int indice=(int)Math.random()*255;
buffer.append((char)indice);
}
content[i]=buffer.toString();
}
index=0;
} /**
* Returns true if the file has more lines to process or false if not
* @return true if the file has more lines to process or false if not
*/
public boolean hasMoreLines(){
return index<content.length;
} /**
* Returns the next line of the simulate file or null if there aren't more lines
* @return
*/
public String getLine(){
if (this.hasMoreLines()) {
System.out.println("Mock: "+(content.length-index));
return content[index++];
}
return null;
} }
Buffer.java
package com.dylan.thread.ch2.c07.task;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; /**
* This class implements a buffer to stores the simulate file lines between the
* producer and the consumers
*
*/
public class Buffer { /**
* The buffer
*/
private LinkedList<String> buffer; /**
* Size of the buffer
*/
private int maxSize; /**
* Lock to control the access to the buffer
*/
private ReentrantLock lock; /**
* Conditions to control that the buffer has lines and has empty space
*/
private Condition lines;
private Condition space; /**
* Attribute to control where are pending lines in the buffer
*/
private boolean pendingLines; /**
* Constructor of the class. Initialize all the objects
*
* @param maxSize
* The size of the buffer
*/
public Buffer(int maxSize) {
this.maxSize = maxSize;
buffer = new LinkedList<>();
lock = new ReentrantLock();
lines = lock.newCondition();
space = lock.newCondition();
pendingLines = true;
} /**
* Insert a line in the buffer
*
* @param line
* line to insert in the buffer
*/
public void insert(String line) {
lock.lock();
try {
while (buffer.size() == maxSize) {
space.await();
}
buffer.offer(line);
System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread()
.getName(), buffer.size());
lines.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} /**
* Returns a line from the buffer
*
* @return a line from the buffer
*/
public String get() {
String line=null;
lock.lock();
try {
while ((buffer.size() == 0) &&(hasPendingLines())) {
lines.await();
} if (hasPendingLines()) {
line = buffer.poll();
System.out.printf("%s: Line Readed: %d\n",Thread.currentThread().getName(),buffer.size());
space.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return line;
} /**
* Establish the value of the variable
*
* @param pendingLines
*/
public void setPendingLines(boolean pendingLines) {
this.pendingLines = pendingLines;
} /**
* Returns the value of the variable
*
* @return the value of the variable
*/
public boolean hasPendingLines() {
return pendingLines || buffer.size() > 0;
} }
Producer.java
package com.dylan.thread.ch2.c07.task;

import com.dylan.thread.ch2.c07.utils.FileMock;

/**
* This class gets lines from the simulate file and stores them in the
* buffer, if there is space in it.
*
*/
public class Producer implements Runnable { /**
* Simulated File
*/
private FileMock mock; /**
* Buffer
*/
private Buffer buffer; /**
* Constructor of the class. Initialize the objects
* @param mock Simulated file
* @param buffer Buffer
*/
public Producer (FileMock mock, Buffer buffer){
this.mock=mock;
this.buffer=buffer;
} /**
* Core method of the producer. While are pending lines in the
* simulated file, reads one and try to store it in the buffer.
*/
@Override
public void run() {
buffer.setPendingLines(true);
while (mock.hasMoreLines()){
String line=mock.getLine();
buffer.insert(line);
}
buffer.setPendingLines(false);
} }
Consumer.java
package com.dylan.thread.ch2.c07.task;

import java.util.Random;

/**
* This class reads line from the buffer and process it
*
*/
public class Consumer implements Runnable { /**
* The buffer
*/
private Buffer buffer; /**
* Constructor of the class. Initialize the buffer
* @param buffer
*/
public Consumer (Buffer buffer) {
this.buffer=buffer;
} /**
* Core method of the consumer. While there are pending lines in the
* buffer, try to read one.
*/
@Override
public void run() {
while (buffer.hasPendingLines()) {
String line=buffer.get();
processLine(line);
}
} /**
* Method that simulates the processing of a line. Waits 10 milliseconds
* @param line
*/
private void processLine(String line) {
try {
Random random=new Random();
Thread.sleep(random.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
Main.java
package com.dylan.thread.ch2.c07.core;

import com.dylan.thread.ch2.c07.task.Buffer;
import com.dylan.thread.ch2.c07.task.Consumer;
import com.dylan.thread.ch2.c07.task.Producer;
import com.dylan.thread.ch2.c07.utils.FileMock; /**
* Main class of the example
*
*/
public class Main { /**
* Main method of the example
* @param args
*/
public static void main(String[] args) {
/**
* Creates a simulated file with 100 lines
*/
FileMock mock=new FileMock(101, 10); /**
* Creates a buffer with a maximum of 20 lines
*/
Buffer buffer=new Buffer(20); /**
* Creates a producer and a thread to run it
*/
Producer producer=new Producer(mock, buffer);
Thread threadProducer=new Thread(producer,"Producer"); /**
* Creates three consumers and threads to run them
*/
Consumer consumers[]=new Consumer[3];
Thread threadConsumers[]=new Thread[3]; for (int i=0; i<3; i++){
consumers[i]=new Consumer(buffer);
threadConsumers[i]=new Thread(consumers[i],"Consumer "+i);
} /**
* Strats the producer and the consumers
*/
threadProducer.start();
for (int i=0; i<3; i++){
threadConsumers[i].start();
}
} }

运行结果:

Mock: 101
Producer: Inserted Line: 1
Mock: 100
Producer: Inserted Line: 2
Mock: 99
Producer: Inserted Line: 3
Mock: 98
Producer: Inserted Line: 4
Mock: 97
Producer: Inserted Line: 5
Mock: 96
Producer: Inserted Line: 6
Mock: 95
Producer: Inserted Line: 7
Mock: 94
Producer: Inserted Line: 8
Mock: 93
Producer: Inserted Line: 9
Mock: 92
Producer: Inserted Line: 10
Mock: 91
Producer: Inserted Line: 11
Mock: 90
Producer: Inserted Line: 12
Mock: 89
Producer: Inserted Line: 13
Mock: 88
Producer: Inserted Line: 14
Mock: 87
Producer: Inserted Line: 15
Mock: 86
Producer: Inserted Line: 16
Mock: 85
Producer: Inserted Line: 17
Mock: 84
Producer: Inserted Line: 18
Mock: 83
Producer: Inserted Line: 19
Mock: 82
Producer: Inserted Line: 20
Mock: 81
Consumer 0: Line Readed: 19
Consumer 0: Line Readed: 18
Consumer 1: Line Readed: 17

...

Mock: 2
Consumer 1: Line Readed: 19
Consumer 2: Line Readed: 18
Consumer 2: Line Readed: 17
Producer: Inserted Line: 18
Mock: 1
Producer: Inserted Line: 19
Consumer 0: Line Readed: 18
Consumer 2: Line Readed: 17
Consumer 1: Line Readed: 16
Consumer 0: Line Readed: 15
Consumer 2: Line Readed: 14
Consumer 0: Line Readed: 13
Consumer 2: Line Readed: 12
Consumer 1: Line Readed: 11
Consumer 0: Line Readed: 10
Consumer 0: Line Readed: 9
Consumer 2: Line Readed: 8
Consumer 0: Line Readed: 7
Consumer 2: Line Readed: 6
Consumer 1: Line Readed: 5
Consumer 1: Line Readed: 4
Consumer 0: Line Readed: 3
Consumer 2: Line Readed: 2
Consumer 0: Line Readed: 1
Consumer 1: Line Readed: 0

Java并发编程实例--19.在一个锁中使用多个条件的更多相关文章

  1. Java并发编程实战 03互斥锁 解决原子性问题

    文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...

  2. Java并发编程:线程和锁的使用与解析

    线程的使用  新建线程 新建一个线程有两种方法:继承Thread类,然后重写run方法:实现Runnable接口,然后实现run方法.实际上Thread类也是实现的Runnable接口,再加上类只能单 ...

  3. java并发编程系列原理篇--JDK中的通信工具类Semaphore

    前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...

  4. Java并发编程:Lock(锁)

    一.synchronized的缺陷 synchronized是java中的一个关键字,也就是说是Java语言内置的特性.那么为什么会出现Lock呢? 在上面一篇文章中,我们了解到如果一个代码块被syn ...

  5. Java并发编程(05):悲观锁和乐观锁机制

    本文源码:GitHub·点这里 || GitEE·点这里 一.资源和加锁 1.场景描述 多线程并发访问同一个资源问题,假如线程A获取变量之后修改变量值,线程C在此时也获取变量值并且修改,两个线程同时并 ...

  6. 【Java并发编程】:多线程环境中安全使用集合API

    在集合API中,最初设计的Vector和Hashtable是多线程安全的.例如:对于Vector来说,用来添加和删除元素的方法是同步的.如果只有一个线程与Vector的实例交互,那么,要求获取和释放对 ...

  7. Java并发编程实例(synchronized)

    此处用一个小程序来说明一下,逻辑是一个计数器(int i):主要的逻辑功能是,如果同步监视了资源i,则不输出i的值,但如果没有添加关键字synchronized,因为是两个线程并发执行,所以会输出i的 ...

  8. Java并发编程-可重入锁

    可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响.在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁. publ ...

  9. 【Java并发编程】4、JDK7中TransferQueue的使用以及TransferQueue与SynchronousQueue的差别

    转自:http://blog.csdn.net/aitangyong/article/details/46472643 JDK7对JDK5中的J.U.C并发工具进行了增强,其中之一就是新增了Trans ...

  10. Java并发编程之显式锁机制

    我们之前介绍过synchronized关键字实现程序的原子性操作,它的内部也是一种加锁和解锁机制,是一种声明式的编程方式,我们只需要对方法或者代码块进行声明,Java内部帮我们在调用方法之前和结束时加 ...

随机推荐

  1. [转帖]Linux中查找大文件两种姿势

    https://rumenz.com/rumenbiji/linux-find-du-max-file.html 使用find命令查找大文件 find命令是Linux系统管理员工具库中最强大的工具之一 ...

  2. 关于信创CPU测试的一些想法和思路

    关于信创CPU测试的一些想法和思路 背景 最近荷兰政府颁布了关于半导体设备出口管制的最新条例. 好像45nm以下的工艺的设备都可能收到限制. 对中国的相关厂商比如长鑫还有华虹的影响应该都比较大. 认为 ...

  3. [转帖]docker 镜像分层原理及容器写时复制

    https://xie.infoq.cn/article/19c98e8b15ff9f610a2ee26bd 一.镜像分层与容器层 在进行docker pull 下载镜像的时候,通过下图可以看到镜像是 ...

  4. [转帖]解释docker单机部署kraft模式kafka集群时,尝试各种方式的网络broker全部不通而启动失败的原因,并提示常见bug关注点

    现象: controller节点与其他两个broker的通信失败.公网ip,宿主机ip,服务名,各种网络方式,都无法成功. 两点提示: 1.bug原因:因为单机内存不够用,设置了较低的 KAFKA_H ...

  5. React Hooks源码深度解析

    作者:京东零售 郑炳懿 前言 React Hooks是React16.8 引入的一个新特性,它允许函数组件中使用state和其他 React 特性,而不必使用类组件.Hooks是一个非常重要的概念,因 ...

  6. echarts第二次渲染不出来的原因

    场景描述 echarts主要用于数据可视化展示 有些时候,我们可能会根据不同的条件,在页面上进行显示和隐藏. 比如说:页面最初展示了数据,当我点击不同的按钮的时候. echarts会对应的展示或者隐藏 ...

  7. HTML直接插入js、css

    简单的小页面可以使用 代码量大的话还是建议引用代码 直接包裹起来 <style>这里添加css代码</style> 加入css标识 <style type="t ...

  8. 1.6 编写双管道ShellCode

    本文将介绍如何将CMD绑定到双向管道上,这是一种常用的黑客反弹技巧,可以让用户在命令行界面下与其他程序进行交互,我们将从创建管道.启动进程.传输数据等方面对这个功能进行详细讲解.此外,本文还将通过使用 ...

  9. 基于队列实现生产者消费者(Python)

    # 进城之间数据隔离 # 进程之间通信(IPC) Inter Process communication # 基于文件 :同一台机器上的多个进程之间通信 # Queue 队列 # 基于socket的文 ...

  10. Linux系统NTP校时的微调模式

    前言: Linux系统有两个时间同步服务:ntpd和chrony,一般较低版本的系统使用ntpd,新版本系统使用chrony. ntpd有两种校时策略slew和step: slew是平滑.缓慢的渐进式 ...