在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. P1111 修复公路 洛谷

    https://www.luogu.org/problem/show?pid=1111 题目背景 A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车.政府派人修复这些公路. 题目描述 给出A地 ...

  2. JAVA获取前一个月的第一天和最后一天

    package com.date; import java.text.SimpleDateFormat; import java.util.Calendar; /** * 默认显示前一个月的第一天和最 ...

  3. 【IntelliJ IDEA】2017.3.4版本永久破解

    [本版本软件包和破解jar在网盘上有    我的网盘--技术--idea破解所需要的] 1.idea官网下载 历史版本 选择2017.3.4版本下载 https://www.jetbrains.com ...

  4. init.rc文件中面启动c++程序,通过jni调用java实现

    </pre><p>注:假设是自己的myself.jar包,还要修改例如以下:</p><p>target/product/core_base.mk PRO ...

  5. C++中的sort函数

    (一)为什么要用c++标准库里的排序函数 Sort()函数是c++一种排序方法之一,学会了这种方法也打消我学习c++以来使用的冒泡排序和选择排序所带来的执行效率不高的问题!因为它使用的排序方法是类似于 ...

  6. [Servlet&amp;JSP] 标准标签

    在JSP的规范中提供了一些标准标签(Standard Tag),全部的容器都支持这些标签,它能够协助编写JSP时降低Scriptlet的使用. 全部的标准标签都使用jsp:作为前置.这些标准标签是在J ...

  7. 经典游戏“大富翁4”存档文件修改器Rich4Editor下载

    下载地址: http://files.cnblogs.com/files/xiandedanteng/Rich4Editor20170614.zip http://files.cnblogs.com/ ...

  8. Java 递归解决 &quot;仅仅能两数相乘的计算器计算x^y&quot; 问题

    /** * 求一个数的乘方 * 求x^y,y是一个正整数. 设计算器仅仅能计算两数相乘,不能一次计算n个数相乘. * 知:2^5=(2^2)^2*2; 2^6=(2^2)^3=((4)^2)*4; 2 ...

  9. UVA 1356 - Bridge(自适应辛普森)

    UVA 1356 - Bridge option=com_onlinejudge&Itemid=8&page=show_problem&category=493&pro ...

  10. 史上最全的CSS hack方式一览 jQuery 图片轮播的代码分离 JQuery中的动画 C#中Trim()、TrimStart()、TrimEnd()的用法 marquee 标签的使用详情 js鼠标事件 js添加遮罩层 页面上通过地址栏传值时出现乱码的两种解决方法 ref和out的区别在c#中 总结

    史上最全的CSS hack方式一览 2013年09月28日 15:57:08 阅读数:175473 做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我 ...