ReentreantLock:重入锁

参考:https://www.cnblogs.com/nullzx/p/4968674.html

一)、 ReentrantLock与synchronized的区别:

1).JDK1.5,在高并发的情况下,ReentrantLock的性能比Synchronized的性能好

2).JDK1.6,中Jvm对其进行了优化,两者差别不大。

3).使用ReentrantLock需要在finally中显示的释放锁,否则,程序出现异常就无法

​ 释放锁。

4).使用Synchronized,JVM虚拟机总会在最后自动的释放synchronized锁。

二)、ReentrantLock的特点

分类: 公平锁/非公平锁

1).公平锁:

​ 特点:保证锁等待队列中各线程是公平的,对锁的获取先进先出

2).非公平锁:

​ 特点:申请锁的线程可能插队,后申请锁的线程可能后进先出

性能比较: 非公平锁的性能优于公平锁,优先选择非公平锁。

构造函数:指定锁的类型

  1. public ReentrantLock(boolean fair)

3). 主要方法:

lock(): 获取锁,若锁已占用,则等待

tryLock(): 尝试获取锁,不等待立即返回,没有获得锁返回false,获得锁返回true

tryLock(long Time, TimeUnit unit): 在指定时间里尝试获取锁

lockInterruptibly(): 获得锁,但优先响应中断

unlock(): 释放锁

三)、Lock()的使用

lock():

特点:

1).返回值为void,没有锁则一直等待,直到获取锁。

2).等待期间,线程不响应中断

  1. public void lock() {
  2. sync.lock();
  3. }

lock()的使用:

  1. import java.util.concurrent.locks.ReentrantLock;
  2. /**
  3. * 测试ReentrantLock获取锁的方法有什么不同
  4. * 使用lock()来获取锁
  5. */
  6. public class Lock implements Runnable{
  7. //保证每一个线程都使用同一把锁
  8. private static ReentrantLock lock = new ReentrantLock();
  9. @Override
  10. public void run() {
  11. while (true) {
  12. //获得锁后,模拟线程进行业务操作
  13. try {
  14. //使用lock()获取锁
  15. lock.lock();
  16. //输出当前获得锁的线程对象
  17. System.out.println("lock " + Thread.currentThread().getName());
  18. Thread.sleep(1000);
  19. } catch (InterruptedException e) {
  20. System.out.println(Thread.currentThread().getName()+ " is Interrupted");
  21. } finally {
  22. //需要在finally中显示的释放锁,否则,程序发生异常,无法释放锁。
  23. lock.unlock();
  24. System.out.println("unlock " + Thread.currentThread().getName());
  25. }
  26. break;
  27. }
  28. }
  29. }

测试类:

  1. public class LockTest {
  2. public static void main(String[] args) {
  3. Lock reentrantLock = new Lock();
  4. Thread first = new Thread(reentrantLock,"FirstThread");
  5. Thread second = new Thread(reentrantLock,"SecondThread");
  6. first.start();
  7. second.start();
  8. try {
  9. Thread.sleep(600);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. //中断线程
  14. /**
  15. * 设置线程的中断位,调用second.interrupt(),线程的中断位置为true,
  16. * 线程的wait()、sleep()、jion()等方法会监控中断位的状态,若状态为true则抛出InterruptedExecption
  17. * 此时,线程不是停止状态,可以执行catch中的业务逻辑。
  18. */
  19. second.interrupt();
  20. }
  21. //结论:使用lock()操作,如果线程未得到锁将会一直等待,直到有其他的线程释放锁,线程在等待期间,不会响应中断
  22. }

结果:

  1. lock FirstThread
  2. unlock FirstThread
  3. lock SecondThread
  4. SecondThread is Interrupted
  5. unlock SecondThread

结果分析:

1).调用lock.lock()获取锁失败,线程则一直在等待。

2).线程等待锁期间,不响应中断。

3).线程调用interrupt()方法,方法本身不会抛出InterruptedExecption,只是改变

​ 了线程的状态位为true, 当前线程的sleep()、wait()、jion()方法识别到了状态位

​ 改变,当状态位为true时抛出InterruptExecption,此时,处于sleep()、wait()

​ jion()状态的线程苏醒,执行catch(){}中的语句,线程抛出InterruptedExecption

后,状态位重新置为false。

四)、lockInterruptibly()的使用:

特点:

1).返回值为void,获取锁,如果获取失败,则一直等待,且优先处理中断

2).获取锁时会先使用Interrupt()判断中断状态并重置中断状态,当中断状态位

​ true时,抛出InterruptedExecption,否则执行获取锁操作

  1. public void lockInterruptibly() throws InterruptedException {
  2. sync.acquireInterruptibly(1);
  3. }
  4. //优先响应中断
  5. public final void acquireInterruptibly(int arg)
  6. throws InterruptedException {
  7. //判断中断状态,Thread.interrupted(),获取当前线程的中断状态,并重置
  8. if (Thread.interrupted())
  9. throw new InterruptedException();
  10. if (!tryAcquire(arg))
  11. doAcquireInterruptibly(arg);
  12. }

lockInterruptibly()的使用:

  1. /**
  2. * 测试使用lockInterruptibly()来获取锁
  3. * lockInterruptibly(): 获取锁,当优先响应中断
  4. */
  5. public class InterruptedLock implements Runnable{
  6. /**
  7. * 创建共有的锁对象
  8. */
  9. private static ReentrantLock lock = new ReentrantLock();
  10. @Override
  11. public void run() {
  12. while (true) {
  13. //获取锁
  14. try {
  15. //lock.lockInterruptibly()方法调用放在try的外部,否则,若线程发生中断,finally调用lock.unlock()会抛出IllegalMonitorStateExecption
  16. lock.lockInterruptibly();
  17. //业务逻辑要放在另一个try里边,因为当线程调用interrupt()会抛出InterruptedException,再finally调用unlock()会抛IllegalMonitorStateExecption
  18. try {
  19. //输出当前获得锁的线程对象
  20. System.out.println("lock " + Thread.currentThread().getName());
  21. //模拟获得锁后的业务逻辑
  22. Thread.sleep(1000);
  23. } finally {
  24. lock.unlock();
  25. //释放锁
  26. System.out.println("unlock "+Thread.currentThread().getName());
  27. break;
  28. }
  29. }catch (InterruptedException e) {
  30. System.out.println(Thread.currentThread().getName() + " is interrupted");
  31. }
  32. }
  33. }
  34. }

测试:

  1. /**
  2. * 测试优选处理中断的锁,在等待期间,可以优先的处理中断
  3. *
  4. */
  5. public class InterruptedLockTest {
  6. public static void main(String[] args){
  7. InterruptedLock interruptedLock = new InterruptedLock();
  8. Thread first = new Thread(interruptedLock, "FirstThread");
  9. Thread second = new Thread(interruptedLock, "SecondThread");
  10. first.start();
  11. second.start();
  12. //线程中断
  13. try {
  14. Thread.sleep(600);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. second.interrupt();
  19. }
  20. }

结果:

  1. lock FirstThread
  2. SecondThread is interrupted
  3. unlock FirstThread
  4. lock SecondThread
  5. unlock SecondThread

结果分析:

1).线程获取锁失败,进入等待状态

2).在线程等待期间,响应中断

注意事项:

lockInterruptibly()在使用时,需要两个try语句,lockInterruptibly()声明在第一个try中,并对应catch处理,业务逻辑在第二个try中,关闭锁也在第二个try的finally中。

  1. while(true){
  2. ...
  3. try{
  4. lock.lockInterruptibly();
  5. try{
  6. ...
  7. }finally{
  8. lock.unlock();
  9. }
  10. }catch(InterruptedExecption e){
  11. }
  12. }

原因:如果使用一层的try,当线程的中断状态为true时,会抛出异常,进行catch处

​ 理,之后在finally释放锁,由于线程未获得锁,调用lock.unlock()会抛出

​ IllegalMonitorStateExecption。

五)、tryLock()的使用:

特点:

1).返回值为void,立即返回获取锁的结果,获取成功返回true,失败返回false

2).尝试获取锁期间,不响应中断。

  1. public boolean tryLock() {
  2. return sync.nonfairTryAcquire(1);
  3. }

tryLock()的使用:

  1. import java.util.concurrent.locks.ReentrantLock;
  2. /**
  3. * tryLock():尝试获取锁
  4. */
  5. public class TryLock implements Runnable{
  6. /**
  7. * 锁对象
  8. */
  9. private static ReentrantLock lock = new ReentrantLock();
  10. @Override
  11. public void run() {
  12. while(true){
  13. //尝试获取锁,立即返回获取结果,成功则返回true,失败返回false
  14. if( lock.tryLock()){
  15. try {
  16. System.out.println("lock "+Thread.currentThread().getName());
  17. Thread.sleep(1000);
  18. } catch (InterruptedException e) {
  19. System.out.println(Thread.currentThread().getName()+" is Interrupted");
  20. }finally{
  21. //释放锁
  22. lock.unlock();
  23. System.out.println("unlock "+ Thread.currentThread().getName());
  24. break;
  25. }
  26. }else{
  27. //获取锁失败
  28. System.out.println("unable lock "+Thread.currentThread().getName());
  29. }
  30. }
  31. }
  32. }

测试类:

  1. public class TryLockTest {
  2. public static void main(String[] args) throws InterruptedException {
  3. TryLock tryLock = new TryLock();
  4. Thread first = new Thread(tryLock,"FirstThread");
  5. Thread second = new Thread(tryLock, "SecondThread");
  6. first.start();
  7. second.start();
  8. Thread.sleep(600);
  9. //中断second线程
  10. second.interrupt();
  11. }
  12. }

结果:

  1. lock FirstThread
  2. unable lock SecondThread
  3. unable lock SecondThread
  4. unable lock SecondThread
  5. unable lock SecondThread
  6. unable lock SecondThread
  7. unable lock SecondThread
  8. unable lock SecondThread
  9. unable lock SecondThread
  10. unable lock SecondThread
  11. unable lock SecondThread
  12. .................... //一大堆获取锁的输出
  13. unlock FirstThread
  14. lock SecondThread
  15. SecondThread is Interrupted
  16. unlock SecondThread

结果分析:

1).使用tryLock(),线程一直判断获取锁

2).线程在尝试获取锁期间,不响应中断

六)、tryLock(long time, TimeUnit unit)的使用

特点:

1).在指定的时间内等待锁,若在指定的时间内获取到锁返回true,未获取到锁,返

​ 会false。

2).在等待锁时优先处理中断,当线程的中断状态为true时,tryLock(long time,

​ TimeUnit unit)抛出InterruptExecption

  1. public boolean tryLock(long timeout, TimeUnit unit)
  2. throws InterruptedException {
  3. return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  4. }
  5. public final boolean tryAcquireNanos(int arg, long nanosTimeout)
  6. throws InterruptedException {
  7. //判断线程的中断状态
  8. if (Thread.interrupted())
  9. throw new InterruptedException();
  10. return tryAcquire(arg) ||
  11. doAcquireNanos(arg, nanosTimeout);
  12. }

tryLock(long time, TimeUnit unit)的使用:

  1. /**
  2. * 在指定时间里等待锁
  3. */
  4. public class TryLockOnTime implements Runnable{
  5. private static ReentrantLock lock = new ReentrantLock();
  6. @Override
  7. public void run() {
  8. while(true) {
  9. //获取锁
  10. try {
  11. //获取锁之前,先判断线程的中断状态,若中断状态为true,抛出InterruptedExecption
  12. if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
  13. try {
  14. System.out.println("lock " + Thread.currentThread().getName());
  15. Thread.sleep(1000);
  16. } finally {
  17. System.out.println("unlock " + Thread.currentThread().getName());
  18. //释放锁
  19. lock.unlock();
  20. }
  21. break;
  22. } else {
  23. System.out.println("unable lock " + Thread.currentThread().getName());
  24. }
  25. } catch (InterruptedException e) {
  26. System.out.println(Thread.currentThread().getName() + " is Interrupted");
  27. }
  28. }
  29. }
  30. }

测试:

  1. public class TryLockOnTimeTest {
  2. public static void main(String[] args) throws InterruptedException {
  3. TryLockOnTime tryLockOnTime = new TryLockOnTime();
  4. Thread first = new Thread(tryLockOnTime, "FirstThread");
  5. Thread second = new Thread(tryLockOnTime, "SecondThread");
  6. first.start();
  7. second.start();
  8. Thread.sleep(1000);
  9. second.interrupt();
  10. }
  11. }

结果:

  1. lock FirstThread
  2. unable lock SecondThread
  3. SecondThread is Interrupted
  4. unlock FirstThread
  5. lock SecondThread
  6. unlock SecondThread

结果分析:

1).使用tryLock(long time, TimeUnit unit)会在指定时间内等待锁,若没有获得锁

​ 返回false,获得锁返回true.

2).等待锁,获取锁时,优先响应中断。

七)、总结

lock(): 获取锁,返回值为void,未获取到锁,线程一直处于等待锁状态,在等待期

​ 不会响应中断。

lockInterruptibly(): 获取锁,返回值为void,未获取到锁,线程一直处于等待锁

​ 状态,在等待锁期间,优先响应中断。

tryLock(): 尝试获取锁,返回值为boolean,未获取到锁,立即返回false,获取到锁,立

​ 即返回true。

tryLock(long timeout, TimeUnit unit):

指定时间内尝试获取锁,返回值为boolean,若在指定时间内未获取到锁,返回

false,获取到锁,返回true,优先响应中断。

ReentreantLock:重入锁的更多相关文章

  1. 重入锁ReentrantLock用法以及如何实现重进入

    在java多线程中,可以使用synchronized实现线程之间的同步互斥,但在jdk1.5中增加了ReentrantLock类也能达到同样的效果,而且在使用上更加灵活,扩展功能上更加强大. 创建My ...

  2. Android 死锁和重入锁

    死锁的定义: 1.一般的死锁 一般的死锁是指多个线程的执行必须同时拥有多个资源,由于不同的线程需要的资源被不同的线程占用,最终导致僵持的状态,这就是一般死锁的定义. package com.cxt.t ...

  3. 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁

    1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...

  4. java ReentrantLock可重入锁功能

    1.可重入锁是可以中断的,如果发生了死锁,可以中断程序 //如下程序出现死锁,不去kill jvm无法解决死锁 public class Uninterruptible { public static ...

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

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

  6. 可重入锁 & 自旋锁 & Java里的AtomicReference和CAS操作 & Linux mutex不可重入

    之前还是写过蛮多的关于锁的文章的: http://www.cnblogs.com/charlesblc/p/5994162.html <[转载]Java中的锁机制 synchronized &a ...

  7. Java并发编程-可重入锁

    可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响.在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁. publ ...

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

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

  9. ReentrantLock(重入锁)以及公平性

    ReentrantLock(重入锁)以及公平性 标签(空格分隔): java NIO 如果在绝对时间上,先对锁进行获取的请求一定被先满足,那么这个锁是公平的,反之,是不公平的,也就是说等待时间最长的线 ...

随机推荐

  1. Netty源码分析之ChannelPipeline(一)—ChannelPipeline的构造与初始化

    Netty中ChannelPipeline实际上类似与一条数据管道,负责传递Channel中读取的消息,它本质上是基于责任链模式的设计与实现,无论是IO事件的拦截器,还是用户自定义的ChannelHa ...

  2. C#方法的定义、调用与调试

    本节内容 1.方法的由来: 2.方法的定义与调用: 3.构造器(一种特殊的方法): 4.方法的重载(Override): 5.如何对方法进行debug: 6.方法的调用与栈* *推荐书目:CLR vi ...

  3. Vue + Js 面试宝典

    https://github.com/rohan-paul/Awesome-JavaScript-Interviewshttps://github.com/nieyafei/front-end-int ...

  4. 清理git仓库

    参考 https://harttle.land/2016/03/22/purge-large-files-in-gitrepo.html https://git-scm.com/docs/git-re ...

  5. 斯坦福机器学习课程 Exercise 习题三

    Exercise 3: Multivariate Linear Regression 预处理数据 Preprocessing the inputs will significantly increas ...

  6. vue 请求图片方法

    node的每一个文件,都是一个域,那么里面所有的变量都不允许被外界引用,除非导出.要使用外界的变量,也必须使用导入的方式来导入.import 文件路径. css可以直接使用import +文件路径导入 ...

  7. 配置Spring Boot 跨域后PUT,DELETE方法出现403Forbidden

    配置类 @Configuration public class CorsConfiguration { @Bean public WebMvcConfigurer corsConfigurer() { ...

  8. csps51(a)

    T1的暴力死掉了...... T3大众分...... T2打了几个小表,发现了一些规律,成功yy出了$O(nlogalogn)$的暴力,拿到了73pts,弥补了爆炸的T1. T1. 考场上看了看,遥远 ...

  9. 线段树合并学习笔记(P4556)

    直入主题: 学习线段树合并..... 从名字就能看出,这个东西要合并线段树..... 线段树怎么能合并呢...... 暴力合就行了啊...... 一次从上往下的遍历,把所有的节点信息暴力合并,然后就没 ...

  10. ElasticSearch(二):文档的基本CRUD与批量操作

    ElasticSearch(二):文档的基本CRUD与批量操作 学习课程链接<Elasticsearch核心技术与实战> Create 文档 支持自动生成文档_id和指定文档_id两种方式 ...