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接口来实现 这样的多线程加锁效果的优点是非常的灵活,我们不在须要对整个函数加锁,并且能 ...
随机推荐
- 利用 CSS animation 和 CSS sprite 制作动画
CSS3 大大强化了制作动画的能力,但是如果要做出图案比较复杂的动画,选择 GIF 依然是一个不错的选择.今天给大家介绍一个使用 CSS animation 配合雪碧图(CSS sprite)来制作动 ...
- LeetCode--寻找数组中心索引
给定一个整数类型的数组 nums,请编写一个能够返回数组“中心索引”的方法. 我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和. 如果数组不存在中心索引,那么我 ...
- sysbench_mysql
ref http://seanlook.com/2016/03/28/mysql-sysbench/ 测试 当执行下面这个sysbench测试mysql的时候,你不知道的可能可能是: 这到底是在测试读 ...
- swift--Xcode7 使用Alamofire框架发送HTTP请求报错
控制台打印的错误信息: Application Transport Security has blocked a cleartext HTTP (http://) resource load sinc ...
- Python基础-奇偶判断调用函数
编写一个函数,输入n为偶数时,调用函数求1/2+1/4+...+1/n,当输入n为奇数时,调用函数 1/1+1/3+...+1/n. 首先写一个n为偶数的函数: def peven(n): s = 0 ...
- PAT 1101 Quick Sort
There is a classical process named partition in the famous quick sort algorithm. In this process we ...
- Codeforces 912D - Fishes
传送门:http://codeforces.com/contest/912/problem/D 本题是一个概率问题——求数学期望. 在一个n×m的方格中,有k个“*”.每个格子里可能有0~1个“*”. ...
- WPF Style设置和模板化Template
WPF样式设置和模板化是一套功能(样式,模板,触发器和演示图版),可以为产品设置统一外观.类似于html的css,可以快速的设置一系列属性值到控件. 案例:ButtonStyle 这里创建了一个目标类 ...
- vue开发规范
一.简介 团队合作中规范文档是必须的,在多人合作的项目只有定义好一定的编码规范才会使得开发井井有序,代码一目了然,下边将谈一下个人对vue使用规范的一些看法. 二.规范案例 1.组件命名 组件文件名应 ...
- 微信小程序如何引用iconfont图标
最近在研究微信小程序,自己写demo的时候想要引用巴里巴巴图标库的图标,于是: @font-face { font-family: 'iconfont'; src: url('iconfont.eot ...