admin管理员组文章数量:1599725
全文概要
本篇将着手线程并发库,即java.util.concurrent包中的几个重要类。线程并发库是jdk1.5引入的,并发库的引入使得多线程开发更加的灵活多变,除此之外,因为java是面向对象的语言,线程并发库的引入让java多线程编程更加正统。本文主要内容如下:
- 介绍Lock,Condition接口;
- 通过使用Lock和Condition来模拟生产者/消费者模型,可以和传统线程实现生产者/消费者模型进行比较阅读。
Lock接口
Lock接口是线程并发库中锁对象的父接口,本文将通过他的实现类ReentrantLock来说明,ReentrantLock是一个可重入的互斥锁,也被称之为“独占锁”,顾名思义,ReentrantLock在同一时刻只能被一个线程拥有,reentrant英文释义就是可重入的,意义就是它可以被单个线程多次获取,相当于synchronized关键字的作用,只不过ReentrantLock是基于对象的。
Condition接口
Condition的作用是对锁进行更加精确的控制,Condition中的await()/signal()/signalAll和Object中wait()/notify()/notifyAll()方法有异曲同工之妙,不同的是Object中的三个方法是基于synchronized关键字,而Condition中的三个方法则需要和Lock联合使用。针对一个Lock对象可以有多个Condition对象,这就是Condition对象更加灵活的原因。
生产者/消费者模型案例
- 代码案例
仓库模型代码:
package com.tml.javaCore.concurrent.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* <p>
* 多线程 生产者-消费者仓库模型
*
* @author Administrator
*
*/
public class Repository {
/*
* 仓库的容量
*/
private int capacity;
/*
* 仓库的实际容量
*/
private int size;
/*
* 独占锁对象,相当于synchronized
*/
private Lock lock;
/*
* 仓库满时的条件
*/
private Condition fullCondition;
/*
* 仓库空时的条件
*/
private Condition emptyCondition;
public Repository(int capacity) {
this.capacity = capacity;
this.size = 0;
lock = new ReentrantLock();
fullCondition = lock.newCondition();
emptyCondition = lock.newCondition();
}
/**
* <p>
* 生产者生产资源
*
* @param produceAmount
* 生产者预生产量
*/
public void produce(int produceAmount) {
//上锁
lock.lock();
try {
while (produceAmount > 0) {
while (size >= capacity) {
System.out.println("has fulled!");
//仓库已经满了,相当于wait()操作,只有当fullCondition.signalAll()才能继续执行
fullCondition.await();
}
/*
* 获取实际的生产量
*/
int actAmount = (size + produceAmount) > capacity ? capacity - size : produceAmount;
size += actAmount;
System.out.println(
Thread.currentThread().getName() + ":has + :" + actAmount + ",the actual size is:" + size);
produceAmount -= actAmount;
// 通知消费者来消费,相当于notifyAll()操作
emptyCondition.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁一般放在finally中
lock.unlock();
}
}
/**
* <p>
* 消费者消费资源
*
* @param consumeAmount
* 消费者预消费量
*/
public void consume(int consumeAmount) {
lock.lock();
try {
while (consumeAmount > 0) {
while (size <= 0) {
System.out.println("empty!");
emptyCondition.await();
}
/*
* 获取实际的消费量
*/
int actAmount = (size < consumeAmount) ? size : consumeAmount;
size -= actAmount;
System.out.println(
Thread.currentThread().getName() + ":has - :" + actAmount + ",the actual size is:" + size);
consumeAmount -= actAmount;
// 通知生产者来生产
fullCondition.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
@Override
public String toString() {
return "Repository [capacity=" + capacity + ", size=" + size + "]";
}
}
测试类代码:
package com.tml.javaCore.concurrent.lock;
/**
* <p>生产者-消费者
* @author Administrator
*
*/
public class TestDemo {
public static void main(String[] args) {
//新建一个容量为100的仓库
Repository repository =new Repository(100);
//模拟生产者,每隔1000毫秒生产23个产品
new Thread(new Runnable() {
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
repository.produce(23);
}
}
},"producer1").start();
//模拟消费者1,每隔2500毫秒消费产品25
new Thread(new Runnable() {
public void run() {
while(true){
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
repository.consume(25);
}
}
},"consumer1").start();
//模拟消费者2,每隔1500毫秒消费产品10
new Thread(new Runnable() {
public void run() {
while(true){
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
repository.consume(10);
}
}
},"consumer2").start();
}
}
- 结果输出
下面是某一次的部分结果输出:
producer1:has + :23,the actual size is:23
consumer2:has - :10,the actual size is:13
producer1:has + :23,the actual size is:36
consumer1:has - :25,the actual size is:11
producer1:has + :23,the actual size is:34
consumer2:has - :10,the actual size is:24
producer1:has + :23,the actual size is:47
consumer2:has - :10,the actual size is:37
consumer1:has - :25,the actual size is:12
producer1:has + :23,the actual size is:35
producer1:has + :23,the actual size is:58
consumer2:has - :10,the actual size is:48
producer1:has + :23,the actual size is:71
consumer1:has - :25,the actual size is:46
consumer2:has - :10,the actual size is:36
producer1:has + :23,the actual size is:59
producer1:has + :23,the actual size is:82
consumer2:has - :10,the actual size is:72
consumer1:has - :25,the actual size is:47
producer1:has + :23,the actual size is:70
consumer2:has - :10,the actual size is:60
producer1:has + :23,the actual size is:83
producer1:has + :17,the actual size is:100
has fulled!
consumer2:has - :10,the actual size is:90
producer1:has + :6,the actual size is:96
consumer1:has - :25,the actual size is:71
producer1:has + :23,the actual size is:94
consumer2:has - :10,the actual size is:84
producer1:has + :16,the actual size is:100
has fulled!
consumer1:has - :25,the actual size is:75
- 结果分析
- 仓库类中定义了一个锁对象,相当于synchronized的作用,由一个锁对象创建出两个条件对象fullCondition(仓库满)和emptyCondition(仓库空);
- 当生产者生产数据的时候,会调用lock.lock()上锁,当生产数量要超过仓库的最大容量的时候,会执行fullCondition.await(),相当于wait()的作用,只有执行fullCondition.signalAll()才能让当前线程继续执行。当生产数量没有超过仓库的最大容量的时候,会调用emptyCondition.signalAll()通知消费者来消费数据;
- 当消费者消费数据的时候,会调用lock.lock()上锁,当消费数据量大于仓库的实际容量的时候,会执行emptyCondition.await(),让消费者线程阻塞,只有线程调用emptyCondition.signalAll()才能让当前线程继续执行。当消费数据量小于仓库的实际容量的时候,会调用fullCondition.signalAll()通知生产者产生数据;
- 最后,当线程的任务执行完毕后,需要调用lock.unlock()释放对象锁。一般释放对象锁都写在finally中,主逻辑写在try中。这就是使用Lock和Condition来实现生产者/消费者模型的案例,后续还会使用阻塞队列的方式实现。
本文标签: ReentrantLockcondition
版权声明:本文标题:深入理解ReentrantLock和Condition 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1728322446a1154001.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论