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的更多相关文章

  1. synchronized关键字,Lock接口以及可重入锁ReentrantLock

    多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...

  2. Java 重入锁 ReentrantLock 原理分析

    1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...

  3. 轻松学习java可重入锁(ReentrantLock)的实现原理

    转载自https://blog.csdn.net/yanyan19880509/article/details/52345422,(做了一些补充) 前言 相信学过java的人都知道 synchroni ...

  4. java 可重入锁ReentrantLock的介绍

    一个小例子帮助理解(我们常用的synchronized也是可重入锁) 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户 ...

  5. 轻松学习java可重入锁(ReentrantLock)的实现原理(转 图解)

    前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...

  6. 17_重入锁ReentrantLock

    [概述] 重入锁可以完全代替synchronized关键字. 与synchronized相比,重入锁ReentrantLock有着显示的操作过程,即开发人员必须手动指定何时加锁,何时释放锁,所以重入锁 ...

  7. Java 显示锁 之 重入锁 ReentrantLock(七)

    ReentrantLock 重入锁简介 重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁.另外,该锁还支持获取锁时的公平与非公平性的选择. 重入锁 ReentrantL ...

  8. 可重入锁ReentrantLock解析

    说到可重入锁,先从AQS的ConditionObject说起,AQS的内部类ConditionObject是构建显示锁条件队列的基础.之前AQS的解析没有说这个内部类,这里和ReentrantLock ...

  9. Java中可重入锁ReentrantLock原理剖析

    本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQue ...

随机推荐

  1. Jquery元素选取、常用方法

    一:常用的选择器:(李昌辉) 基本选择器 $("#myDiv") //匹配唯一的具有此id值的元素 $("div") //匹配指定名称的所有元素 $(" ...

  2. Hibernate4.2.4入门(二)——一对多的映射关系

    一.前言 前面我们已经学过hibernate的基础,学会增删改查简单的操作,然而我们数据库中存在着1对多,多对1,多对多的关系,hibernate又是基于ORM基础上的开源框架,可以让我们不用去编写S ...

  3. 模块化你的JS代码

    为什么要使用模块模式? 因为在全局作用域中声明的变量和函数都自动成为全局对象Window的属性,这经常会导致命名冲突,还会导致一些非常重要的可维护性难题,全局变量越多,引入错误BUG的概率就越大!所以 ...

  4. 简单的学习心得:网易云课堂Android开发第六章SQLite与ContentProvider

    一.SQLite 1.基本操作: (1)创建数据库:在SQLiteOpenHelper的子类构造器中创建. (2)创建表:在SQLiteOpenHelper的子类onCreate方法中,调用execS ...

  5. text-overflow

    text-overflow:clip | ellipsis 默认值:clip 适用于:所有元素 clip: 当对象内文本溢出时不显示省略标记(...),而是将溢出的部分裁切掉. ellipsis: 当 ...

  6. 在Windows中玩转Docker Toolbox

    最近在研究虚拟化,容器和大数据,所以从Docker入手,下面介绍一下在Windows下怎么玩转Docker. Docker本身在Windows下有两个软件,一个就是Docker,另一个是Docker ...

  7. PHP语法(一):基础和变量

    相关链接: PHP语法(一):基础和变量 PHP语法(二):数据类型.运算符和函数 PHP语法(三):控制结构(For循环/If/Switch/While) 最近有个H5项目的需求,需要服务端,考察过 ...

  8. WPF 自定义列表筛选 自定义TreeView模板 自定义ListBox模板

    有很多项目,都有数据筛选的操作.下面提供一个案例,给大家做参考. 左侧是数据源,搜索框加TreeView控件,右侧是ListBox控件.在左侧数据列点击添加数据,然后点击确定,得到所筛选的数据. 下面 ...

  9. POJ2104 K-th Number [分块做法]

    传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求 ...

  10. linux网络编程tcp

    之前学习的时候笔记没有保存好,这次重新编写一个案例. 客户端实现程序代码: #include <string.h> #include <stdlib.h> #include & ...