架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock
ReentrantLock
有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级。
this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决方案,后面jdk干脆就提供了一个Lock类。
伪代码:
Lock lock = new ReentrantLock();//新建一个lock
Condition condition = lock.newCondition();//获取条件
method1(){
try{
lock.lock();
代码块;
lock.unlock();
后续代码块;
}
}
method2(){
try{
lock.lock();
代码块;
lock.signal();
}
}
单condition操作:
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- public class UseCondition {
- private Lock lock = new ReentrantLock();
- private Condition condition = lock.newCondition();
- public void method1(){
- try {
- lock.lock();
- System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
- Thread.sleep(3000);
- System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
- condition.await(); // Object wait
- System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public void method2(){
- try {
- lock.lock();
- System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
- Thread.sleep(3000);
- System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
- condition.signal(); //Object notify
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public static void main(String[] args) {
- final UseCondition uc = new UseCondition();
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- uc.method1();
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- uc.method2();
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
执行结果:
解释:线程1调用method1方法,线程2调用同一对象的method2方法,线程1先启动,线程1获取锁,进入method1的代码块,线程2也启动了,单是线程2被锁定,直到线程1发出lock.unlock()了,线程1才将锁释放,这时线程2获取锁,执行method2的代码块,线程2发出lock.signal(); 线程1才继续执行后续代码块。
多condition操作:
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.ReentrantLock;
- public class UseManyCondition {
- private ReentrantLock lock = new ReentrantLock();
- private Condition c1 = lock.newCondition();
- private Condition c2 = lock.newCondition();
- public void m1(){
- try {
- lock.lock();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m1等待..");
- c1.await();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m1继续..");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public void m2(){
- try {
- lock.lock();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m2等待..");
- c1.await();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m2继续..");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public void m3(){
- try {
- lock.lock();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m3等待..");
- c2.await();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m3继续..");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public void m4(){
- try {
- lock.lock();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
- c1.signalAll();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public void m5(){
- try {
- lock.lock();
- System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
- c2.signal();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- public static void main(String[] args) {
- final UseManyCondition umc = new UseManyCondition();
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- umc.m1();
- }
- },"t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- umc.m2();
- }
- },"t2");
- Thread t3 = new Thread(new Runnable() {
- @Override
- public void run() {
- umc.m3();
- }
- },"t3");
- Thread t4 = new Thread(new Runnable() {
- @Override
- public void run() {
- umc.m4();
- }
- },"t4");
- Thread t5 = new Thread(new Runnable() {
- @Override
- public void run() {
- umc.m5();
- }
- },"t5");
- t1.start(); // c1
- t2.start(); // c1
- t3.start(); // c2
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- t4.start(); // c1
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- t5.start(); // c2
- }
- }
执行结果:
解释:t1、t2线程都是用第一个condition c1,t3线程用第二个condition c2,t4线程发出c1.signalAll() 唤醒t1和t2线程,t5发出c2.signal()唤醒t3线程。
ReentrantReadWriteLock
读写分离锁,读读共享、写写互斥、读写互斥。
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
- public class UseReentrantReadWriteLock {
- private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
- private ReadLock readLock = rwLock.readLock();
- private WriteLock writeLock = rwLock.writeLock();
- public void read(){
- try {
- readLock.lock();
- System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
- Thread.sleep(3000);
- System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- readLock.unlock();
- }
- }
- public void write(){
- try {
- writeLock.lock();
- System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
- Thread.sleep(3000);
- System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- writeLock.unlock();
- }
- }
- public static void main(String[] args) {
- final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.read();
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.read();
- }
- }, "t2");
- Thread t3 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.write();
- }
- }, "t3");
- Thread t4 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.write();
- }
- }, "t4");
- t1.start();
- t2.start();
- // t1.start(); // R
- // t3.start(); // W
- // t3.start();
- // t4.start();
- }
- }
解释:t1和t2都是读,是共享的,可同时获得readLock同时进入read方法执行。t1是读和t3是写,是互斥的,只有t1执行完t3才能执行。t3、t4都是写,是互斥的,只有等t3执行完t4才能继续。
架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock的更多相关文章
- synchronized关键字,Lock接口以及可重入锁ReentrantLock
多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...
- Java 重入锁 ReentrantLock 原理分析
1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...
- 轻松学习java可重入锁(ReentrantLock)的实现原理
转载自https://blog.csdn.net/yanyan19880509/article/details/52345422,(做了一些补充) 前言 相信学过java的人都知道 synchroni ...
- java 可重入锁ReentrantLock的介绍
一个小例子帮助理解(我们常用的synchronized也是可重入锁) 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户 ...
- 轻松学习java可重入锁(ReentrantLock)的实现原理(转 图解)
前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...
- 17_重入锁ReentrantLock
[概述] 重入锁可以完全代替synchronized关键字. 与synchronized相比,重入锁ReentrantLock有着显示的操作过程,即开发人员必须手动指定何时加锁,何时释放锁,所以重入锁 ...
- Java 显示锁 之 重入锁 ReentrantLock(七)
ReentrantLock 重入锁简介 重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁.另外,该锁还支持获取锁时的公平与非公平性的选择. 重入锁 ReentrantL ...
- 可重入锁ReentrantLock解析
说到可重入锁,先从AQS的ConditionObject说起,AQS的内部类ConditionObject是构建显示锁条件队列的基础.之前AQS的解析没有说这个内部类,这里和ReentrantLock ...
- Java中可重入锁ReentrantLock原理剖析
本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQue ...
随机推荐
- JqueryDataTable的使用(.Net平台)
上一篇随笔提到了MvcPager,最近用到了一款前端JQ插件------DataTable(简称DT),很好用. DT是一款前端插件,和后端完全分离开,就这点来看,我就特别喜欢. 一.使用DT,需要以 ...
- 一步步实现ABAP后台导入EXCEL到数据库【1】
在SAP的应用当中,导入.导出EXCEL文件的情况是一个常见的需求,有时候用户需要将大量数据定期导入到SAP的数据库中.这种情况下,使用导入程序在前台导入可能要花费不少的时间,如果能安排导入程序为后台 ...
- MPAndroidChart 3.0——LineChart(折线图)
显示效果 MPAndroidChart每一种图表的基本使用方式都基本相同 了解一种图表的实现 参考项目源码其他的图表也就差不多哩 在布局文件中定义 <com.github.mikephil.ch ...
- 一位资深程序员大牛给予Java初学者的学习路线建议
java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈 ...
- 长按TextField或TextView显示中文的粘贴复制
首先要确保手机当前系统为中文,只需要在 plist 文件中添加 Localized resources can be mixed = YES 就行了
- UICollectionViewCell--查找cell上的按钮点击后,对应的是哪个cell
实际写项目会碰到各种各样的问题,废话不多说 按钮添加到cell时,根据是直接添加到self还是self.contentView上,在点击方法里找到btn的父视图 我是直接添加到self上,所以只有一层 ...
- nginx+tomcat https实践
1. 安装ssl'证书 使用Let's Encrypt 的免费证书: 下载源代码: git clone https://github.com/letsencrypt/letsencrypt 我时阿里云 ...
- 国产方法论之 ReDoIt -- 惟思捷
最近上了PMP课程,感觉受益匪浅,思路有被打开. 很同意一个观点“国人很擅长做事,但是不擅长总结出解决问题的通用框架和方法论”. 为了能提高中小企业生产力我最近成了一个小的软件咨询公司取名“惟思捷”, ...
- 基础拾遗------redis详解
基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...
- hadoop-2.7.1伪分布环境搭建
1.准备Linux环境 1.0 点击VMware快捷方式,右键打开文件所在位置 -> 双击vmnetcfg.exe -> VMnet1 host-only ->修改subnet i ...