1.定义
重入锁ReentrantLock,支持重入的锁,表示一个线程对资源的重复加锁。
2.底层实现
每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。
3.使用样例

eg:

import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockTest implements Runnable{public static int i = 100;public static ReentrantLock rl = new ReentrantLock();@Overridepublic void run() {while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}rl.lock();if(i>0){System.out.println(Thread.currentThread().getName() + " : " + i--);}rl.unlock();}}public static void main(String[] args) {ReentrantLockTest rlt = new ReentrantLockTest();Thread t1 = new Thread(rlt);Thread t2 = new Thread(rlt);t1.start();t2.start();}}

中断响应
synchronized:线程等待锁,要么获得锁继续执行,要么保持等待。
ReentrantLock:等待锁的过程中,可以根据需求取消对锁的请求。
eg:

import java.util.concurrent.locks.ReentrantLock;public class IntLock implements Runnable {int lock;public static ReentrantLock lock1 = new ReentrantLock();public static ReentrantLock lock2 = new ReentrantLock();public IntLock(int lock){this.lock = lock;}@Overridepublic void run() {try{if(lock == 1){try{lock1.lockInterruptibly();      // 如果当前线程未被中断,则获取锁。}catch(Exception e){e.printStackTrace();}lock2.lockInterruptibly();System.out.println(Thread.currentThread().getId()+"执行完毕");}else{lock2.lockInterruptibly();try{Thread.sleep(1000);}catch(Exception e){}lock1.lockInterruptibly();}}catch(Exception e){e.printStackTrace();}finally{if(lock1.isHeldByCurrentThread()){      //查询当前线程是否保持此锁lock1.unlock();}if(lock2.isHeldByCurrentThread()){      //查询当前线程是否保持此锁lock2.unlock();}System.out.println(Thread.currentThread().getId()+":线程退出");}}public static void main(String[] args) throws InterruptedException {IntLock l1 = new IntLock(1);IntLock l2 = new IntLock(2);Thread t1 = new Thread(l1);Thread t2 = new Thread(l2);t1.start();t2.start();Thread.sleep(2000);t2.interrupt();         //中断线程,不中断,则产生死锁}}

锁申请等待限时
如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class TimeLock implements Runnable {public static ReentrantLock rl = new ReentrantLock();@Overridepublic void run() {try {if(rl.tryLock(5, TimeUnit.SECONDS)){Thread.sleep(6000);System.out.println(Thread.currentThread().getId()+"执行完毕");}else{System.out.println(Thread.currentThread().getId()+"get lock failed");}} catch (InterruptedException e) {e.printStackTrace();}finally{if(rl.isHeldByCurrentThread())rl.unlock();}}public static void main(String[] args) {TimeLock tl = new TimeLock();Thread t1 = new Thread(tl);Thread t2 = new Thread(tl);t1.start();t2.start();}}

公平锁

在ReentrantLock中很明显可以看到其中同步包括两种,分别是公平的FairSync和非公平的NonfairSync。公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。默认情况下ReentrantLock是通过非公平锁来进行同步的,包括synchronized关键字都是如此,因为这样性能会更好。

public ReentrantLock(boolean fair) //如果此锁应该使用公平的排序策略,则该参数为 true

import java.util.concurrent.locks.ReentrantLock;public class FairLock implements Runnable{public static ReentrantLock rl = new ReentrantLock(true);@Overridepublic void run() {while(true){try {rl.lock();System.out.println(Thread.currentThread().getName()+" : get lock");} catch (Exception e) {}finally{rl.unlock();}}}public static void main(String[] args) {FairLock fl = new FairLock();Thread t1 = new Thread(fl,"Thread_One");Thread t2 = new Thread(fl,"Thread_Two");t1.start();t2.start();}}

在重入锁的实现中,包含3个要素

1.原子状态,使用CAS操作来存储当前锁的状态,判断锁是否被别的线程持有
2.等待队列,所有没有请求到锁的线程,会进入到队列进行等待,待有线程释放锁后,系统能从等待队列唤醒一个线程继续工作。
3.阻塞原语park()和unpark(),用来挂起和恢复线程,没有得到锁的线程会被挂起

Condition
Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的;而Condition是需要与"互斥锁"/"共享锁"捆绑使用的。

Condition函数列表
void await() //造成当前线程在接到信号或被中断之前一直处于等待状态。
boolean await(long time, TimeUnit unit) //造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
long awaitNanos(long nanosTimeout) //造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
void awaitUninterruptibly() //造成当前线程在接到信号之前一直处于等待状态。
boolean awaitUntil(Date deadline) //造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。
void signal() //唤醒一个等待线程。
void signalAll() //唤醒所有等待线程。

eg:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockCondition implements Runnable {public static ReentrantLock rl = new ReentrantLock();public static Condition condition = rl.newCondition();@Overridepublic void run() {rl.lock();try {condition.await();  //与此 Condition 相关的锁以原子方式释放System.out.println("Thread is going on");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{rl.unlock();}}public static void main(String[] args) throws InterruptedException {ReentrantLockCondition rlc = new ReentrantLockCondition();Thread t1 = new Thread(rlc);t1.start();Thread.sleep(3000);rl.lock();condition.signal();rl.unlock();}}

ReentrantLock和synchronized关键字的区别

1.ReentrantLock在等待锁时可以使用lockInterruptibly()方法选择中断, 改为处理其他事情,而synchronized关键字,线程需要一直等待下去。同样的,tryLock()方法可以设置超时时间,用于在超时时间内一直获取不到锁时进行中断。
2.ReentrantLock可以实现公平锁,而synchronized的锁是非公平的。
3.ReentrantLock拥有方便的方法用于获取正在等待锁的线程。
4.ReentrantLock可以同时绑定多个Condition对象,而synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件,如果要和多于一个条件关联时,只能再加一个额外的锁,而ReentrantLock只需要多次调用newCondition方法即可。

一般情况下都是用synchronized实现同步,除非下列情况使用ReentrantLock:

1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候

转载于:https://www.cnblogs.com/Ch1nYK/p/9245153.html

java多线程---重入锁ReentrantLock相关推荐

  1. Java多线程——重入锁ReentrantLock源码阅读

    上一章<AQS源码阅读>讲了AQS框架,这次讲讲它的应用类(注意不是子类实现,待会细讲). ReentrantLock,顾名思义重入锁,但什么是重入,这个锁到底是怎样的,我们来看看类的注解 ...

  2. java中的账户冻结原理_java可重入锁(ReentrantLock)的实现原理

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

  3. Java 重入锁 ReentrantLock 原理分析

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

  4. 并发编程-19AQS同步组件之重入锁ReentrantLock、 读写锁ReentrantReadWriteLock、Condition

    文章目录 J.U.C脑图 ReentrantLock概述 ReentrantLock 常用方法 synchronized 和 ReentrantLock的比较 ReentrantLock示例 读写锁R ...

  5. Java 可重入锁内存可见性分析

    转载自 深度好文 | Java 可重入锁内存可见性分析 一个习以为常的细节 之前在做 ReentrantLock 相关的试验,试验本身很简单,和本文相关的简化版如下:(提示:以下代码均可左右滑动) p ...

  6. java 可重入锁 clh_Java并发编程系列-(4) 显式锁与AQS

    4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...

  7. java可重入锁与不可重入锁

    所谓重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的. synchronized 和   ReentrantLock 都是可重入锁. 可重 ...

  8. Java 可重入锁 不可重入锁

    文章目录 Java 可重入锁 & 不可重入锁 概述 论证synchronized是可重入锁: 论证Lock是可重入锁: 自定义不可重入锁: Java 可重入锁 & 不可重入锁 概述 可 ...

  9. 重入锁ReentrantLock详解

    重入锁ReentrantLock,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁.除此之外,该锁的还支持获取锁时的公平和非公平性选择. 在AQS实现中,当一个线程调用Mute ...

最新文章

  1. 15.2 java中迭代器的注意事项
  2. vue sync用法
  3. 计算机网络——速率相关的性能指标
  4. jacascript 立即执行函数(IIFE)与闭包
  5. linux echo 变量 字符串,echo命令 – 输出字符串或提取Shell变量的值 – 运维那些事...
  6. 数据结构之二叉树_二叉排序树(严蔚敏C语言版)
  7. 编程漫谈及计算机硬件简介
  8. Java出现The import javax.servlet cannot be resolved 的解决方法
  9. matlab中单位格式,[转载]matlab中的数据显示格式-format
  10. Windows Server 2008 R2更新永恒之蓝 补丁包方法
  11. EXCEL 学习步骤总结
  12. 易飞计件工资的设计及应用
  13. 使用GDI/GDI+绘制到D3D9缓冲区的方法
  14. GCF(4)----手机认证相关知识
  15. 杰理之实现蓝牙三方通话功能【篇】
  16. 不用升级 普通MP4也能看PDF ---PDFtoJPG
  17. 五 、Kotlin学习之命名参数默认参数
  18. WIN11跳过开机启动OOBE界面进入系统方法
  19. java castor_Castor功能与应用参考二
  20. LimeSDR 信号生成发射与接收分析

热门文章

  1. 深度学习的时间序列分类
  2. 直接灰度变换法matlab,数字图像处理-灰度变换(附MATLAB代码)
  3. 微擎安装遇到一个问题,大佬救救我
  4. 一文搞定贷款利息计算
  5. WordPress主题CorePress
  6. 导进去然后这边就报错了 看修改也看不懂
  7. SQL Server 事务日志已满的解决方案
  8. Tomcat日志记录post请求参数
  9. Security:在 SIEM 上运用 Elastic Security
  10. CSS3-KeyFrames