一个锁可能关联了一个或多个条件。这些条件可以在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. [转帖]3.3.7. 自动诊断和建议报告SYS_KDDM

    https://help.kingbase.com.cn/v8/perfor/performance-optimization/performance-optimization-6.html#sys- ...

  2. [转帖]模拟enq: TX - row lock contention争用

    https://www.modb.pro/db/623036 enq: TX - row lock contention它表示一个事务正在等待另一个事务释放被锁定的行.这种等待事件通常发生在并发访问数 ...

  3. 通过mat获取OOM时对象信息的方法与过程

    通过mat获取OOM时对象信息的方法与过程 背景 如果谁的耐心不好, 就让他去看MAT里的objects信息. 有项目出现了OOM的情况 我在公司这边有一台内存比较高的Win10机器. 然后帮助同事进 ...

  4. ESXi重置密码以及修改网络IP地址的方法

    Study From https://www.cnblogs.com/mk21/p/15784082.html 前期公司有部分虚拟化的服务器因为只通过vCenter进行管理. 导致密码遗失. 最近因为 ...

  5. 【字符串,哈希】【Yandex】Yandex7736

    2023.6.30 Problem Link 定义一个串 \(S\) 是好的,当且仅当 \(S\) 可以不断消去相邻两个相同字符直至消空.给定一个长为 \(n\) 的字符串 \(s\),求有多少个有序 ...

  6. 释放搜索潜力:基于ES(ElasticSearch)打造高效的语义搜索系统,让信息尽在掌握

    释放搜索潜力:基于ES(ElasticSearch)打造高效的语义搜索系统,让信息尽在掌握[1.安装部署篇--简洁版],支持Linux/Windows部署安装 效果展示 PaddleNLP Pipel ...

  7. 4.1 C++ STL 动态链表容器

    List和SList都是C++ STL中的容器,都是基于双向链表实现的,可以存储可重复元素的特点.其中,List内部的节点结构包含两个指针一个指向前一个节点,一个指向后一个节点,而SList只有一个指 ...

  8. 开发必备,开源 or 免费的 AI 编程助手

    AI 大模型的火热,让开发圈近来如虎添翼,各种各样基于 AI 技术的开发者工具和新范式不断涌现,尤其是 Github 和 OpenAI 共同推出的 Copilot X ,更是一骑绝尘.本文推荐一些开源 ...

  9. ICLR 2024 | Mol-Instructions: 面向大模型的大规模生物分子指令数据集

    Mol-Instructions: 面向大模型的大规模生物分子指令数据集 发表会议:ICLR 2024 论文标题:Mol-Instructions: A Large-Scale Biomolecula ...

  10. 扩展说明: 指令微调 Llama 2

    这篇博客是一篇来自 Meta AI,关于指令微调 Llama 2 的扩展说明.旨在聚焦构建指令数据集,有了它,我们则可以使用自己的指令来微调 Llama 2 基础模型. 目标是构建一个能够基于输入内容 ...