在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实现线程间通信的更多相关文章

  1. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  2. Java并发——使用Condition线程间通信

    线程间通信 线程之间除了同步互斥,还要考虑通信.在Java5之前我们的通信方式为:wait 和 notify.Condition的优势是支持多路等待,即可以定义多个Condition,每个condit ...

  3. java多线程系列5-死锁与线程间通信

    这篇文章介绍java死锁机制和线程间通信 死锁 死锁:两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象. 同步代码块的嵌套案例 public class MyLock { // 创建两 ...

  4. Java笔记(二十)……线程间通信

    概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...

  5. java线程间通信:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...

  6. Java多线程:线程间通信之Lock

    Java 5 之后,Java在内置关键字sychronized的基础上又增加了一个新的处理锁的方式,Lock类. 由于在Java线程间通信:volatile与sychronized中,我们已经详细的了 ...

  7. java多线程与线程间通信

    转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...

  8. java并发之线程间通信协作

    在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界 ...

  9. 说说Java线程间通信

    序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在 ...

随机推荐

  1. easyui 带参数的datagride

    <table id="tt" style="width:100%;height:355px" url="../aowei/Handler/Han ...

  2. input 输入框限制

    只能输入数字和一个小数点 转自: https://www.jianshu.com/p/c26bfb0dfd8d <label> <input id="tranlimit_b ...

  3. CenOs7安装oracle图文详细过程(02)

    原创作品,转载请在文章头部(显眼位置)注明出处:https://www.cnblogs.com/sunshine5683/p/10011574.html 8.修改用户限制 vim /etc/secur ...

  4. 快速幂取模(POJ 1995)

    http://poj.org/problem?id=1995 以这道题来分析一下快速幂取模 a^b%c(这就是著名的RSA公钥的加密方法),当a,b很大时,直接求解这个问题不太可能 利用公式a*b%c ...

  5. 解决docker启动错误 error creating overlay mount to /var/lib/docker/overlay2

    原文 最近在centos7.1使用docker运行redis镜像,出现下面的错误: /usr/bin/docker-current: Error response from daemon: error ...

  6. 工厂方法模式(GOF23)

    耦合关系直接决定着软件面对变化时的行为 主要对模块之间的关系进行整理,依赖关系倒置(依赖反转),变化快的东西不能影响到变化慢的东西 用封装机制来隔离易变的对象,抽象部分(不易变)和细节部分(可能容易变 ...

  7. js中变量声明有var和没有var的区别

    转js中var用与不用的区别 2015年07月13日 16:08:22 阅读数:3627 Javascript声明变量的时候,虽然用var关键字声明和不用关键字声明,很多时候运行并没有问题,但是这两种 ...

  8. template 的使用

    插件介绍:template 是一个高性能的JavaScript模板引擎. 插件特性: 1.性能卓越,执行速度快(mustache 与 tmpl 的20多倍): 2.支持运行时调试,可精准定位异常模板所 ...

  9. C#-创建并添加TXT文件

    public static void WriteToText(string txtContent, string txtPath) { using (FileStream fs = new FileS ...

  10. android 原生 MediaPlayer 和 MediaCodec 的区别和联系(三)

    目录:     (4)Android 官方网站 对 MediaCodec的介绍 注:编解码器特定数据(Code-specific Data,简写为csd) 部分结合网上资料加入了补充和个人理解.请悉知 ...