一个锁可能关联了一个或多个条件。这些条件可以在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. [转帖]oracle 审计日志清理

    https://www.cnblogs.com/bangchen/p/7268086.html   --进入审计日志目录: cd $ORACLE_BASE/admin/$ORACLE_SID/adum ...

  2. [转帖]《Linux性能优化实战》笔记(22)—— 网络丢包问题分析

    所谓丢包,是指在网络数据的收发过程中,由于种种原因,数据包还没传输到应用程序中,就被丢弃了.这些被丢弃包的数量,除以总的传输包数,也就是我们常说的丢包率.丢包率是网络性能中最核心的指标之一.丢包通常会 ...

  3. [转帖]美国出口管制条例(EAR)简介

    https://zhuanlan.zhihu.com/p/87962305 第一节.美国出口管制法律体系 下述一系列法律.法规及规则,构成美国完整的出口管理制度,是美国各相关执法部门执法的主要法律依据 ...

  4. 高性能Redis服务器注意事项

    摘要 昨天简单理了理安装与配置相关的 但是很多比较重要的核心性能参数并没有进行学习与探讨 就基于昨天理解不深入的地方进行进一步的学习与了解 希望能够提高Redis-Server的性能. 第一部分: 规 ...

  5. 简单定位占用最高CPU的java进程信息

    公司里面一个应用不小心点击就会导致系统性能下降很明显. 性能组的同事定位到了, 我这里以学习的态度重现一下这个过程. 1. 问题再现 产品一个非常大数据量的帮助, 点击之后就会占用非常多的cpu 因为 ...

  6. Linux 开启防火墙 避免非干系人误操作的处理

    公司里面进行系统集成测试. 不想让开发能够更改我的服务器信息, 但是改密码又太麻烦了. 想了想还是用 防火墙好一些. 第一步 开启防火墙 systemctl enable firewalld syst ...

  7. Linux下PG数据库计划任务定期备份恢复的方法

    注意事项 PG数据库需要注意的一点是需要安装OSSP-UUID的组件才能使用. 本次使用最除了冷备之外 最简单的 pg_dump和pg_restore的操作 的方式来进行处理 务必定期演练保证数据备份 ...

  8. Python设计模式:你的代码真的够优雅吗?

    当涉及到代码优化时,Python作为一种高级编程语言,具有广泛的应用领域和强大的功能.在软件开发中,设计模式是一种被广泛采用的解决问题的方案,它提供了一种在特定情境中重复使用的可行方案.在Python ...

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

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

  10. ABP-VNext 用户权限管理系统实战03---动态api调用并传递token

    一.使用动态api的目的 ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 HttpClient 或者其他低级的HTTP功能调用远程服 ...