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接口来实现 这样的多线程加锁效果的优点是非常的灵活,我们不在须要对整个函数加锁,并且能 ...
随机推荐
- python tkinter模块 创建窗口V1.2
先上图 代码如下 #-*-coding:utf-8-*- import os from tkinter import * root=Tk() root.title('执行窗口') "&quo ...
- 00.pip安装包
pip安装更换镜像源 pip install 包名 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com pip导出和导入 ...
- git 的简单使用(2)
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了: $ rm test.txt 你可以使用 git rm test.txt来删除 然后用git commit -m " ...
- 【模板】求1~n的整数的乘法逆元
洛谷3811 先用n!p-2求出n!的乘法逆元 因为有(i-1)!-1=i!-1*i (mod p),于是我们可以O(n)求出i!-1 再用i!-1*(i-1)!=i-1 (mod p)即是答案 #i ...
- hdu2007 平方和与立方和【C++】
平方和与立方和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- ActiveMQ学习总结(1)——ActiveMQ快速入门
1.下载ActiveMQ 去官方网站下载:http://activemq.apache.org/ 2.运行ActiveMQ 解压缩apache-activemq-5.5.1-bin.zip,然后双击a ...
- NOI2017爆零记[AFO]
WC2017 12分……全省第一…… APIO2017 4分……全省第二…… 千言万语汇成两个表格 NOI2017 114分(笔试100+一试4+二试5+A类5)……全省第三…… 全场最菜…… day ...
- [luoguP3275] [SCOI2011]糖果(差分约束)
传送门 差分约束裸题 但是坑! 有一个点是长为10W的链,需要逆序加边才能过(真是玄学) 还有各种坑爹数据 开longlong ——代码 #include <cstdio> #includ ...
- 源代码:windows文件切割与合并
#include <Windows.h> #include <vector> #include <string> using namespace std; //推断 ...
- Android LaunchAnyWhere (Google Bug 7699048)漏洞具体解释及防御措施
開始 近日,Google修复一个组件安全的漏洞LaunchAnyWhere(Google Bug 7699048). 这个漏洞属于Intend Based提取漏洞,攻击者利用这个漏洞,能够突破了应用间 ...