Java多线程技术-Lock/Condition
在java1.5中Lock对象来实现同步的效果,而且使用上更方便。
使用ReentrantLock实现同步
public class MyService {
private Lock lock = new ReentrantLock();
public void methodA(){
try {
lock.lock();
System.out.println("methodA begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void methodB(){
try {
lock.lock();
System.out.println("methodB begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
new Thread(()->service.methodA()).start();
new Thread(()->service.methodA()).start();
new Thread(()->service.methodB()).start();
new Thread(()->service.methodB()).start();
}
}
测试结果:调用lock.lock()的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢,效果和synchronized一样。
methodA begin threadName=Thread-0 time=1516242293668
methodA end threadName=Thread-0 time=1516242298669
methodA begin threadName=Thread-1 time=1516242298669
methodA end threadName=Thread-1 time=1516242303671
methodB begin threadName=Thread-2 time=1516242303671
methodB end threadName=Thread-2 time=1516242308672
methodB begin threadName=Thread-3 time=1516242308672
methodB end threadName=Thread-3 time=1516242313674
使用Condition实现等待/通知
public class MyService {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void await(){
try {
lock.lock();
System.out.println("await时间为"+System.currentTimeMillis());
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signal(){
try {
lock.lock();
System.out.println("signal时间为"+System.currentTimeMillis());
condition.signal();
} finally {
lock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
new Thread(()->service.await()).start();
Thread.sleep(3000);
service.signal();
}
}
相似处:
1. 在使用Condition的await方法和signal方法之前比较先调用lock.lock(),否则会抛出异常,跟wait和nofity一样,需在synchronized的代码里运行一样
2. Object.wait() --> Condition.await(). Object.notify()--> Condition.signal(), Object.notifyAll() -->Condition.signalAll()
优点:
在一个Lock对象里面可以创建多个Condition实例,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度上更加灵活。
使用多个Condition实现通知部分线程
public class MyService {
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
public void awaitA(){
try {
lock.lock();
System.out.println("begin awaitA时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionA.await();
System.out.println("end awaitA时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitB(){
try {
lock.lock();
System.out.println("begin awaitB时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionB.await();
System.out.println("end awaitB时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalAll_A(){
try {
lock.lock();
System.out.println("signalAll_B 时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionA.signalAll();
} finally {
lock.unlock();
}
}
public void signalAll_B(){
try {
lock.lock();
System.out.println("signalAll_B 时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionB.signalAll();
} finally {
lock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
new Thread(()->service.awaitA()).start();
new Thread(()->service.awaitB()).start();
Thread.sleep(3000);
service.signalAll_A();
}
}
测试结果:线程B没有被唤醒
begin awaitA时间为1516244219035Thread name=Thread-0
begin awaitB时间为1516244219036Thread name=Thread-1
signalAll_B 时间为1516244222035Thread name=main
end awaitA时间为1516244222035Thread name=Thread-0
生产者和消费者
public class MyList {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private volatile List<String> list = new ArrayList<>(10);
public void get() {
try {
System.out.println("get,listSize="+list.size());
lock.lock();
while (list.size() == 0) {
System.out.println("get 等待,ThreadName=" + Thread.currentThread().getName());
condition.await();
}
System.out.println("get -1");
list.remove(0);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}
public void set() {
try {
System.out.println("set,listSize="+list.size());
lock.lock();
while (list.size() == 10) {
System.out.println("set 等待,ThreadName=" + Thread.currentThread().getName());
condition.await();
}
System.out.println("set+1");
list.add("A");
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyList consumer = new MyList();
for(int i =0;i<10;i++){
new Thread(()->{
while(true){ consumer.set();}
}).start();
new Thread(()->{
while(true){ consumer.get();}
}).start();
}
}
}
ReentrantReadWriteLock
ReentrantLock具有完全互斥排他的效果,即在同一时间内只有一个线程在执行ReentrantLock.lock()方法后面的任务。但是效率相对低下,而是用ReentrantReadWriteLock读写锁,可以相对提高效率。读写锁也就是有两个锁,一个是和读相关的锁,也称共享锁,一个是和写相关的锁,也叫排它锁。只有读读锁之间不互斥,其他都互斥。
读读锁不互斥的例子
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read(){
try {
lock.readLock().lock();
System.out.println("获得读锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
new Thread(()->service.read()).start();
new Thread(()->service.read()).start();
}
}
测试结果:几乎同时获得读锁,说明它们不互斥的
获得读锁Thread-0 1516246020468
获得读锁Thread-1 1516246020469
读写互斥的例子
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read(){
try {
lock.readLock().lock();
System.out.println("获得读锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
public void write(){
try {
lock.writeLock().lock();
System.out.println("获得写锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
new Thread(()->service.read()).start();
new Thread(()->service.write()).start();
}
}
测试结果:写操作需要等待读锁释放后才能获得
获得读锁Thread-0 1516246209130
获得写锁Thread-1 1516246219132
Java多线程技术-Lock/Condition的更多相关文章
- Java多线程技术学习笔记(二)
目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...
- 赶紧收藏!王者级别的Java多线程技术笔记,我java小菜鸡愿奉你为地表最强!
Java多线程技术概述 介绍多线程之前要介绍线程,介绍线程则离不开进程. 首先 , 进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元: 线程:就 ...
- Java多线程技术:实现多用户服务端Socket通信
目录 前言回顾 一.多用户服务器 二.使用线程池实现服务端多线程 1.单线程版本 2.多线程版本 三.多用户与服务端通信演示 四.多用户服务器完整代码 最后 前言回顾 在上一篇<Java多线程实 ...
- Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock
在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...
- java多线程技术核心
1.进程的三大特征: 独立性:拥有自己的独立的地址空间,一个进程不可以直接去访问其他进程的地址空间. 动态性:是一个系统中活动的指令的集合. 并发性:单个进程可以在多个处理器上并发进行,互不影响. 2 ...
- Java多线程基础——Lock类
之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信.在jdk1.5以后,JAVA提供了Lock类来实现和synchronized ...
- java多线程技术之条件变量
上一篇讲述了并发包下的Lock,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇 ...
- Java多线程技术学习笔记(一)
目录: 概述 多线程的好处与弊端 JVM中的多线程解析 多线程的创建方式之一:继承Thread类 线程的状态 多线程创建的方式之二:实现Runnable接口 使用方式二创建多线程的好处 多线程示例 线 ...
- Java多线程的~~~Lock接口和ReentrantLock使用
在多线程开发.除了synchronized这个keyword外,我们还通过Lock接口来实现这样的效果.由Lock接口来实现 这样的多线程加锁效果的优点是非常的灵活,我们不在须要对整个函数加锁,并且能 ...
随机推荐
- sratookit
sratookit 下载后解压 tar -zxvf sratoolkit.2.8.2-1-ubuntu64.tar.gz 移动到专门安装生物信息软件的目录下 mv sratoolkit.2.8.2-1 ...
- Object.create() __https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
Object.create() 方法会使用指定的原型对象及其属性去创建一个新的对象. 语法 Object.create(proto[, propertiesObject]) 参数 proto 新创建对 ...
- MFC CAD控制权问题
begineditorcommand(); 隐藏对话框 把控制权交给CAD completeeditorcommand(); 完成交互返回到应用程序 canceleditorcommand CAD被 ...
- for循环中索引值和取值的迷惑
利用for循环和range从100——10,倒序讲所有的偶数添加到一个新列表中,然后对列表的元素进行筛选,将能被4整除的数留下来. even = []for i in range(100,9,-1): ...
- 搭建 Seafile 专属网盘
准备域名 任务时间:15min ~ 20min 域名注册 如果您还没有域名,可以在腾讯云上选购,过程可以参考下面的视频. 视频 - 在腾讯云上购买域名 域名解析 域名购买完成后, 需要将域名解析到实验 ...
- 一个电商项目的Web服务化改造6:单元测试4步走,构造数据、执行操作、断言、回滚
最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA. 有点挑战,做完了,会有很大进步. 单元测试,在很早之前的文章已经介绍过. 可以在这里看到相关的 ...
- 【hiho一下 第145周】智力竞赛
[题目链接]:http://hihocoder.com/contest/hiho145/problem/1 [题意] [题解] 设f[i][j]表示做对i道题,做错j道题能够到达的最好状态是什么; 这 ...
- Leetcode 49.字母异位词分组
字母异位词分组 给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", "tea", " ...
- MongoDB整库备份与还原以及单个collection备份、恢复
备份前的检查> show dbsMyDB 0.0625GBadmin (empty)bruce 0.0625GBlocal (empty)test 0.0625GB> use MyDBsw ...
- hdu_1020_Encoding_201310172120
Encoding Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...