在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. JAVA基础之——String、StringBuilder、StringBuffer区别和使用场景

    本文主要讲解String.StringBuilder.StringBuffer区别和应用场景 本文以jdk1.8为例 1 String 操作过程:每次赋值时新建一个String对象. 2 String ...

  2. java的内存区域

    java的内存区域分为程序计数器.java虚拟机栈.本地方法栈.java堆.方法区.运行时常量池. 1.程序计数器 2.java虚拟机栈 3.本地方法栈 4.java堆(新生代和老年代) 5.方法区( ...

  3. HDU P2089

    题目大意为,统计区间内不含4和62的数字的个数: 老实说,看到这题我是抵触的..... 基本上是数位DP的板子,话说数位DP好像全是模板题吧: 预处理,有关的整区间的数字个数: 调用已有的区间,求解0 ...

  4. 洛谷P4716 【模板】最小树形图(朱刘算法)

    题意 题目链接 Sol 朱刘算法?感觉又是一种神仙贪心算法 大概就是每次贪心的用每个点边权最小的入边更新答案,如果不行的话就缩起来找其他的边 不详细说了,丢链接走人.. #include<bit ...

  5. 【PyQt5 学习记录】002:添加部件及网格布局

    #!/usr/bin/python3 # -*- coding:utf-8 -*- import sys from PySide2.QtWidgets import (QApplication, QW ...

  6. Vue.js小案例(1)

    数据绑定 数据绑定是vue.js的基础.本例中就是利用了vue.js的v-model指令在表单元素上创建双向数据绑定. <!--这是我们的View--> <div id=" ...

  7. 解决 客户端连接 mysql5.7 Plugin 'mysql_native_plugin' is not loaded错误

    进入mysql数据库,修改数据库的内容  1, use mysql; 2,update user set authentication_string=""  where User= ...

  8. robbe-1.2发布-支持最新版本的friso+WinNT下php各版本的dll

    robbe是建立在friso中文分词组建上的一个高性能php中文分词扩展.(只支持UTF-8编码) robbe-1.2: 1. friso近几天发布1.3了, 接口有些许变化, 更改robbe适合最新 ...

  9. input标签添加上disable属性在ios端字体颜色不兼容的问题

    input[disabled],input:disabled,input.disabled{ color: #3e3e3e; -webkit-text-fill-color: #3e3e3e; -we ...

  10. LinkedList源码疑问记录

    早上看linkedList源码时候,对于它的初始化一直不太明白.如下: transient int size = 0; /** * Pointer to first node. * Invariant ...