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

  创建MyService.java类,代码如下:

package com.lit.reentreantlock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class MyService {
private Lock lock = new ReentrantLock() ;
public void testMethod(){
lock.lock();
for(int i = 0 ; i < 5 ; i++){
System.out.println("ThreadName = "+Thread.currentThread().getName()+" "+(i+1));
}
lock.unlock();
}
}

  调用ReentrantLock对象的lock()方法获取锁,unlock()方法释放锁。

  再创建MyThread.java,代码如下:

package com.lit.reentreantlock;

public class MyThread extends Thread{
private MyService service ; public MyThread(MyService service){
this.service = service ;
}
@Override
public void run() {
service.testMethod();
}
}

  运行类Run.java如下:

package com.lit.reentreantlock;

public class Run {
public static void main(String[] args) {
MyService service = new MyService() ; MyThread t1 = new MyThread(service) ;
MyThread t2 = new MyThread(service) ;
MyThread t3 = new MyThread(service) ;
MyThread t4 = new MyThread(service) ;
MyThread t5 = new MyThread(service) ;
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}

  程序运行结果如下:

ThreadName = Thread-1   1
ThreadName = Thread-1 2
ThreadName = Thread-0 1
ThreadName = Thread-0 2
ThreadName = Thread-3 1
ThreadName = Thread-3 2
ThreadName = Thread-2 1
ThreadName = Thread-2 2
ThreadName = Thread-4 1
ThreadName = Thread-4 2

  从线程的运行结果来看,线程之间的打印是分组打印的,打印完毕将锁释放其他线程才可以继续打印。

  以上简单的介绍了ReentrantLock的用法,ReentrantLock是重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。实现重进入需要解决一下两个问题:

  (1)线程再次获取锁。 锁需要去识别获取锁的线程是否是当前占据锁的线程,如果是,则再次成功获取锁。

  (2)锁的最终释放。线程重复n次获取了锁,随后在第n次获取锁之后对锁进行进行释放,其他线程之后能够获取到该锁。那么锁的最终释放要求锁在获取时候对于每一次成功获取进行自增计数,计数表示被重复获取的次数,而锁被释放时,计数自减,当计数减为0时表示锁获取成功。

  ReentrantLock的实现是依靠队列同步器AbstractQueuedSynchronizer实现的,ReentrantLock内部定义了一个静态内部类,也就是AbstractQueuedSynchronizer的子类Sync,Sync自定义实现了AbstractQueuedSynchronizer的模板方法。以非公平锁为例,ReentrantLock在获取锁定的时候通过调用的代码清单如下。

final boolean nonfairTryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取同步状态
int c = getState();
//如果锁没有被占用
if (c == 0) {
//CAS设置同步状态
if (compareAndSetState(0, acquires)) {
//设置独占模式下的获得同步状态的线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果锁被占用
//判断是否为当前线程再次获取锁
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//计数 +1
setState(nextc);
return true;
}
return false;
}

  该方法增加了再次获取同步状态的处理逻辑:通过判断当前线程是否为获取锁的线程来决定获取才做是否成功,如果是获取锁的线程再次请求获取锁,则对同步状态进行计数加1并返回true,表示获取同步状态成功。

  成功获取锁的线程再次获取锁,只是增加了同步状态值,这也要求ReentrantLock在释放同步状态时减少同步状态的值,该方法的代码清单如下:

 protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}

  如果该锁被获取了n次,那么锁的释放在前(n-1)次必须返回false,而只有同步状态完全释放了才返回true。可以看到该方法将同步状态是否为0作为最终释放的条件,当同步状态为0时,占有线程设置为null,并返回true,表示释放成功。

重入锁ReentrantLock用法以及如何实现重进入的更多相关文章

  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 (转)(学习记录)

    重入锁(ReentrantLock)是一种递归无阻塞的同步机制.以前一直认为它是synchronized的简单替代,而且实现机制也不相差太远.不过最近实践过程中发现它们之间还是有着天壤之别. 以下是官 ...

  9. Java并发包4--可重入锁ReentrantLock的实现原理

    前言 ReentrantLock是JUC提供的可重入锁的实现,用法上几乎等同于Synchronized,但是ReentrantLock在功能的丰富性上要比Synchronized要强大. 一.Reen ...

随机推荐

  1. MySQL-JDBC Loadbalance深入解析

    背景说明 公司的整个电商系统搭建在华为云上,根据老总的估计,上线3个月之后日订单量会达到百万级别,保守估计3个月之后总订单个数预计会有5千万.MySQL单表达到千万级别,就会出现明显的性能问题.根据如 ...

  2. Python入门--13--爬虫一

    URL的格式一般为(带方括号的是可选的): protocol://hostname[:port]/path/[;parameters][?query]#fragment URL由三部分组成: 第一部分 ...

  3. MyBatis的参数,不能传入null

    今天在调试的过程中发现一个bug,把传入的参数写到查询分析器中执行没有问题,但是在程序中执行就报错:org.springframework.jdbc.UncategorizedSQLException ...

  4. java 文件复制操作

    本案例采用第三方 jar 包完成,commons-io-2.5.jar, 这个 jar 对文件操作非常方便,大家可以尝试使用一下. 这里贴一个简单的 demo 供大家使用 import java.io ...

  5. numpy数组之读写文件

    目录 通过 numpy 读写 txt 或 csv 文件 通过 numpy 读写 npy 或 npz 文件 读写 npy 文件 读写 npz 文件 通过 h5py 读写 hdf5 文件 简单读取 通过切 ...

  6. 安装 node-sass 的不成功

    昨天安装项目依赖的包,差不多都装好了,然后就卡在了node-sass上,各种报错. 报错一.gyp ERR! stack Error: Can't find Python executable &qu ...

  7. InteliJ 安装PlantUML插件

    打开InteliJ点击Setting 在[Plugins]搜索PlantUML插件,点击绿色的Install安装 然后重启 完成

  8. 7.Java web—tomcat9部署

    1)安装 在此之前要安装 好jdk和jre 下载绿色版 http://tomcat.apache.org/ 解压至:D:\Program Files (x86)\tomcat9 环境变更path添加两 ...

  9. iOS Application Security

    文章分A,B,C,D 4个部分. A) iOS Application Security 下面介绍iOS应用安全,如何分析和动态修改app. 1)iOS Application security Pa ...

  10. mysql 建立utf8字符集数据库

    CREATE DATABASE `evaluate` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;