java Concurrent包学习笔记(三):ReentrantLock
一、可重入性的理解
从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大。两者都是同一个线程每进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
比如下面的代码片段:第一个lock没有unlock,就再次获取了lock
private Lock lock = new ReentrantLock();
lock.lock();
执行一段代码
lock.lock();
再行执行一段代码
lock.unlock();
lock.unlock();
lock()的流程图:

unlock()的流程如下:

二、主要方法
jdk8中,ReentrantLock的方法:
- lock():
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态 - tryLock():马上返回,拿到lock就返回true,不然返回false。
- tryLock((long timeout TimeUnit unit),马上返回,拿到lock就返回true,不然等到超时时间返回false。
lockInterruptibly(), 可中断加锁,即在锁获取过程中不处理中断状态,而是直接抛出中断异常,由上层调用者处理中断。ReentrantLock的中断和非中断加锁模式的区别在于:线程尝试获取锁操作失败后,在等待过程中,如果该线程被其他线程中断了,它是如何响应中断请求的。lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断。
- unLock(): 释放锁
- newCondition():返回用来与此 Lock 实例一起使用的 Condition 实例
那么,为什么要分为这两种模式呢?这两种加锁方式分别适用于什么场合呢?根据它们的实现语义来理解,我认为lock()适用于锁获取操作不受中断影响的情况,此时可以忽略中断请求正常执行加锁操作,因为该操作仅仅记录了中断状态(通过Thread.currentThread().interrupt()操作,只是恢复了中断状态为true,并没有对中断进行响应)。如果要求被中断线程不能参与锁的竞争操作,则此时应该使用lockInterruptibly方法,一旦检测到中断请求,立即返回不再参与锁的竞争并且取消锁获取操作(即finally中的cancelAcquire操作)。
三、Conditon对象
Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition。
Condition类能实现synchronized和wait、notify搭配的功能,另外比后者更灵活,Condition可以实现多路通知功能,也就是在一个Lock对象里可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择的进行线程通知,在调度线程上更加灵活。
synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在这个对象上。线程开始notifyAll时,需要通知所有的WAITING线程,没有选择权,会有相当大的效率问题。
看下面的例子:
Student类
package reentrantlock.demo; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @author Administrator
* @date 2018/12/24
*/
public class Student { private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition(); public void awaitA() {
try {
lock.lock();
System.out.println("学生A:等待吃饭");
conditionA.await();
System.out.println("学生A:开始吃饭");
Thread.sleep(2000);
System.out.println("学生A:吃完");
}catch (InterruptedException e) {
}finally {
lock.unlock();
System.out.println("学生A释放了锁======");
}
} public void awaitB() {
try {
lock.lock();
System.out.println("学生B:等待吃饭");
conditionB.await();
System.out.println("学生B:开始吃饭");
Thread.sleep(2000);
System.out.println("学生B:吃完");
}catch (InterruptedException e) {
}finally {
lock.unlock();
System.out.println("学生B释放了锁======");
}
} public void signalAll_A() {
try{
lock.lock();
System.out.println("唤醒学生A");
conditionA.signalAll();
} finally {
lock.unlock();
}
} public void signalAll_B() {
try{
lock.lock();
System.out.println("唤醒学生B");
conditionA.signalAll();
} finally {
lock.unlock();
}
} }
测试类
package reentrantlock.demo; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @author Administrator
* @date 2018/12/24
*/ public class ReentrantLockTest1 {
class StudentThreadA implements Runnable{
Student student;
StudentThreadA(Student student){
this.student = student;
}
public void run(){
student.awaitA();
}
} class StudentThreadB implements Runnable{
Student student;
StudentThreadB(Student student){
this.student = student;
}
public void run(){
student.awaitB();
}
} public static void main(String[] args){
ReentrantLockTest1 rl = new ReentrantLockTest1();
Student student = new Student();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(rl.new StudentThreadA(student));
executorService.submit(rl.new StudentThreadB(student));
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
student.signalAll_A();
executorService.shutdown(); }
}
运行结果可知,只唤醒了学生A
学生A:等待吃饭
学生B:等待吃饭
唤醒学生A
学生A:开始吃饭
学生A:吃完
学生A释放了锁======
四、Condition类和Object类
- Condition类的awiat方法和Object类的wait方法等效
- Condition类的signal方法和Object类的notify方法等效
- Condition类的signalAll方法和Object类的notifyAll方法等效
五、公平锁和非公平锁
Lock lock=new ReentrantLock(true);//公平锁
Lock lock=new ReentrantLock(false);//非公平锁
六、synchronized和ReentrantLock的区别:
1.等待可中断
在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待. tryLock(long timeout, TimeUnit unit)
2.公平锁
按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁. new RenentrantLock(boolean fair)
3.绑定多个Condition
通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal();
java Concurrent包学习笔记(三):ReentrantLock的更多相关文章
- java Concurrent包学习笔记(一):ExecutorService
一.介绍 ExecutorService是java.util.concurrent包中的一个线程池实现接口.其有两个实现类: 1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能 ...
- java Concurrent包学习笔记(四):BlockingQueue
一.BlockingQueue概述 1.阻塞的含义 BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞.被阻塞的情况主要有如下两种: ,当一个线程对 ...
- java Concurrent包学习笔记(五):Semaphore
一.Semaphore 是什么 信号量Semaphore是一个并发工具类,用来控制可同时并发的线程数,其内部维护了一组虚拟许可,构造函数初始化的时候可以指定许可的总数量 每次线程执行操作时先通过ac ...
- java Concurrent包学习笔记(七):ConcurrentHashMap
(注意:以下讲解的ConcurrentHashMap是jdk 1.8的) 一.ConcurrentHashMap的数据结构 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上 ...
- java Concurrent包学习笔记(六):Exchanger
一.概述 Exchanger 是一个用于线程间协作的工具类,Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据.这两个线程通过exchange 方法 ...
- java Concurrent包学习笔记(二):CountDownLatch和CyclicBarrier
一.CountDownLatch CountDownLatch一个线程同步的工具,是的一个或者多个线程等待其他线程操作完成之后再执行. CountDownLatch通过一个给定的数值count来进行初 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- java.util.concurrent包学习笔记(一)Executor框架
类图: 其实从类图我们能发现concurrent包(除去java.util.concurrent.atomic 和 java.util.concurrent.locks)中的内容并没有特别多,大概分为 ...
- java package 包 学习笔记
编译命令示例: javac -d . Main.java 注:带参数-d自动建立文件目录, 只使用javac 则需要手工创建目录 把 class文件打包 jar命令 jar cvf T.jar *; ...
随机推荐
- Win7系统不能记忆窗口大小与位置解决方法
似在某此系统优化后,无意发现系统在注销或重启后,打开资源管理器,它以默认大小及位置显示. 对于习惯自定义操作来说,甚为不便,遍找方法未有奏效者,但总萦绕心头,时时记起. 今日再找问题解决方法,难兄难弟 ...
- Django的Rbac介绍1
1.django的权限管理叫做RBAC 我们在百度上查看RBAC的概念如下 基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的 ...
- C# 创建WebService的简单示例
工具Visual Studio 2013 1.创建一个空的Web应用程序. 2.鼠标右击项目,添加->新建项 选择Web服务(ASMX),点击添加.一个简单的webservice就创建完成了.
- Python爬虫项目--爬取自如网房源信息
本次爬取自如网房源信息所用到的知识点: 1. requests get请求 2. lxml解析html 3. Xpath 4. MongoDB存储 正文 1.分析目标站点 1. url: http:/ ...
- powerdesigner中实现PDM到MYSQl数据库的转换
一.使用PowerDesigner制作建库脚本 1.设计CDM(Conceptual Data Model) 2.选择 Tools -> Generate Physical Data Model ...
- js的urlencode
function urlencode (str) { str = (str + '').toString(); return encodeURIComponent(str).replace(/!/g, ...
- select into tb_temp2 from tb_temp1 创建临时表实现上一个、下一个功能,使用完毕就删除临时表
好久没有写过Sql了,今天遇到一个问题,业务逻辑是: 一个商品可以属于多个分类,在显示商品详情的时候,要求可以点击“上一个”,“下一个” 查看和该商品在同一个分类下的其他商品,商品具有排序号. 这样我 ...
- 编码补充 daty 6
---恢复内容开始--- 1. 用id求内存地址 id 查询内存地址 name = 'alex' print(id(name)) li = [1,2,3] print(id(li)) 结果: 2. ...
- 13.Mysql触发器
13.触发器13.1 创建触发器定义:触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合.语法:create trigger 触发器名称 触发时机 触发事件 on 表名 ...
- Activity和Intent