在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. ObjectDataSource配合存储过程(采用数据集)的使用(删除可以解决,但是编辑出错好像它的方法也无法解决

    原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] ObjectDataSource是比较有意思的一个东西 通过在网络上遍访各位高手,终于自己有了一些心得体会。现总结 ...

  2. 关于代码调试de那些事

    原文出处:http://www.wklken.me/posts/2014/11/23/how-to-debug.html 关于代码调试de那些事 1.你得明白你在做什么, 保持清醒 2.想清楚了再写代 ...

  3. hdu2448 / 费用流 / harbin赛区c题

    题(自)目(己)错(英)综(语)复(太)杂(差),关系理了半小时+翻译才看明白,看明白之后,直接建图,费用流击杀./简单题. 2A:有的地方,可用互通的要建双向边! #include<cstdi ...

  4. webstorm(二):拼写warning

    逼死强迫症之对拼写进行检查,警告 typo:in word “msgfromfather”

  5. python和linux的环境设置/PATH

    一.python的环境设置 1.输出path列表: pi@raspberrypi:~$ pythonPython 3.4.0 (default, Jul 1 2014, 09:37:01) [GCC ...

  6. 【Lucene】具体解释Lucene全文检索的信息写入与读取

    Lucene的大致结构图: 信息写入索引库的过程: 读取信息的过程: 以下是一个向索引库写入信息与读取信息的样例: public void testCreateIndex() throws Excep ...

  7. c++ struct与class的差别

    从语法上,在C++中(仅仅讨论C++中).class和struct做类型定义时仅仅有两点差别: (一)默认继承权限. 假设不明白指定,来自class的继承依照private继承处理.来自struct的 ...

  8. javaproject积累——树形结构的操作

    近期一直被树形结构整的非常头大,又是递归.又是循环.可是,好在我们在经历了千辛万苦后.最终弄出来了.事实上就是组织机构的常规操作,有些是我们过度设计.有些是我们想错了.而对数的逻辑读取,我们就属于想错 ...

  9. Solidworks如何显示装饰螺纹线

    1 工具-选项   2 文档属性-上色的装饰螺纹线   3 这样我再插入装饰螺纹线的时候就有效果了

  10. dm8127/8148下怎样进行dsplink的编写

    样例:从A8读入1080p的yuv420sp的数据给dsplink,在dsp 中建立一个link(做一些图像处理的工作).然后将yuv420sp的数据发送到videoM3做jpeg编码,然后在传递到A ...