用ReentrantLock和Condition实现线程间通信
在Java多线程中,除了使用synchronize关键字来实现线程之间的同步互斥,还可以使用JDK1.5中新增的RetrantLock类来实现同样的效果。RetrantLock类的扩展功能也更加强大,比如具有嗅探锁定,多路分支通知等功能,在使用上也比synchronize更为灵活。
借助于Condition对象,RetrantLock可以实现类似于Object的wait和notify/notifyAll功能。使用它具有更好的灵活性,在一个Lock对象里面可以创建多个Condition(对象监视器)实例,线程对象可以注册在指定的Condition对象中,从而可以有选择性的进行线程通知,实现多路通知功能,在调度线程上更加灵活。
每一个 Lock 可以有任意数据的 Condition 对象, Condition 是与 Lock 绑定的,所以就有 Lock 的公平性特性:如果是公平锁,线程为按照FIFO的顺序从 Condition.await 中释放,如果是非公平锁,那么后续的锁竞争就不保证FIFO顺序了。
下面是一个生产者、消费者的示例:
/*
* 买家线程,当书店中有书的时候买书
*/
public class Buyer extends Thread {
private BookStore bookStore; public Buyer(BookStore bookStore) {
this.bookStore = bookStore;
} @Override
public void run() {
while (true) {
bookStore.removeBook();
}
}
}
/*
* 售货员线程,当书店中还有空位,买进书籍
*/
public class Seller extends Thread {
private BookStore bookStore;
public Seller(BookStore bookStore) {
this.bookStore = bookStore;
} @Override
public void run() {
while (true) {
bookStore.addBook();
}
}
}
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; /*
* 书店类
*/
public class BookStore {
private ArrayList books = new ArrayList();
private ReentrantLock lock = new ReentrantLock(false);
private Condition buyCondition = lock.newCondition();
private Condition sellCondition = lock.newCondition();
public void addBook() {
lock.lock();
while (books.size() >= 1) {
try {
System.out.println(Thread.currentThread().getName() + "等待图书售出");
sellCondition.await(); //售货员等待书店出现空位
} catch (InterruptedException e) {
e.printStackTrace();
}
}
books.add(1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "购入了一本书,剩余:" + books.size());
buyCondition.signal(); //通知买家买书
lock.unlock();
} public void removeBook() {
lock.lock();
while (books.size() <= 0) {
try {
System.out.println(Thread.currentThread().getName() + "等待购入图书");
buyCondition.await(); //买家等待书店进书
} catch (InterruptedException e) {
e.printStackTrace();
}
}
books.remove(0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买了一本书,剩余:" + books.size());
sellCondition.signal(); //通知售货员进书
lock.unlock();
}
}
/*
* 测试类
*/
public class Test {
public static void main(String[] args) {
BookStore bookStore = new BookStore();
Buyer[] buyers = new Buyer[5];
Seller sellers;
//创建5个买家线程,负责买书
for(int i = 0; i < 5; i++) {
buyers[i] = new Buyer(bookStore);
}
//创建售货员线程,负责进书
sellers = new Seller(bookStore);
//启动线程
sellers.start();
for(int i = 0; i < 5; i++) {
buyers[i].start();
}
}
}
运行结果:
从结果我们可以看到售货员线程和买家线程是交替运行的,这就是因为两类线程分别绑定了两个不同的Condition:buyCondition,sellCondition。从而实现了两类线程的交替唤醒。
用ReentrantLock和Condition实现线程间通信的更多相关文章
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...
- Java并发——使用Condition线程间通信
线程间通信 线程之间除了同步互斥,还要考虑通信.在Java5之前我们的通信方式为:wait 和 notify.Condition的优势是支持多路等待,即可以定义多个Condition,每个condit ...
- java多线程系列5-死锁与线程间通信
这篇文章介绍java死锁机制和线程间通信 死锁 死锁:两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象. 同步代码块的嵌套案例 public class MyLock { // 创建两 ...
- Java笔记(二十)……线程间通信
概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
- Java多线程:线程间通信之Lock
Java 5 之后,Java在内置关键字sychronized的基础上又增加了一个新的处理锁的方式,Lock类. 由于在Java线程间通信:volatile与sychronized中,我们已经详细的了 ...
- java多线程与线程间通信
转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...
- java并发之线程间通信协作
在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界 ...
- 说说Java线程间通信
序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在 ...
随机推荐
- sql sever 执行较大的文件脚本
1.用管理员身份打开cmd工具 2.执行命令 osql -S localhost -U sa -P 123456 -i D:/test.sql -S 服务器地址 本地可简写 . -U 用户名 -P ...
- Java学习--jsp基础语法
<%! %>和<% %>的区别: <%! //1.可定义方法 //2.可定义static方法 //3.可定义static属性 //4.不可以使用out对象 %> ...
- linux的日常经常使用的命令
现在经常用到linux命令,又时候回忘记,我就做个小笔记,大家也可以补充补充.....可以评论一下,我会截图做笔记的 netstat -ntlp //查看当前系统进程和端口等信息 tail -f fi ...
- HDU 2041--超级楼梯(递推求解)
Description 有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? Input 输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每 ...
- SqlServer示例数据库Northwind(一)——实体关系
在学习Spss统计分析.EA画实体关系图.PowerDesigner画数据库模型图等时,苦于找不到一个好的实例.由于实际工作中项目使用的表结构属于公司的商业保密内容,且在和大家交流时,其结构大家也不熟 ...
- 线程(Thread)和异常
线程Thread 实现多线程有两种方式: 1.继承Thread类(本质也是实现Runnable接口的一个实例) Thread类源码 public class Thread implements Run ...
- [转]Shared——回调函数是什么
本文内容转自知乎 作者:no.body 链接:https://www.zhihu.com/question/19801131/answer/27459821 回调函数(callback)是什么? 什么 ...
- Angular入门教程四
4.8依赖注入DI 通过依赖注入,ng想要推崇一种声明式的开发方式,即当我们需要使用某一模块或服务时,不需要关心此模块内部如何实现,只需声明一下就可以使用了.在多处使用只需进行多次声明,大大提高可复用 ...
- <Android 应用 之路> MPAndroidChart~BubbleChart(气泡图) and RadarChart(雷达图)
简介 MPAndroidChart是PhilJay大神给Android开发者带来的福利.MPAndroidChart是一个功能强大并且使用灵活的图表开源库,支持Android和iOS两种,这里我们暂时 ...
- Java设计模式—桥梁模式
终于又碰到了一个简单点的模式了. 桥梁模式也叫做桥接模式,定义如下: 将抽象和实现解耦,使得两者可以独立地变化. 这句话也太难理解了,桥梁模式是为了解决类继承的缺点而设计 ...