在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. TYVJ4623 球球大作战·生存

    时间: 500ms / 空间: 65536KiB / Java类名: Main 背景 小天很喜欢玩球球大作战这个游戏,大家也应该都玩过.游戏规则是:移动自己的球,移动到别人的球(一定要比自己的球小)的 ...

  2. gridview无数据源实现更新数据库(即断开更新数据库)

    原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...

  3. php——数据库操作之规范性

    今天在写一个项目,上传到服务器的时候出现500的错误,找了半天最后是因为数据库更新数据的语句写的不规范, 询问同事之后,同事说,数据库的增删改查语句写的不规范的时候有的时候会报错有的时候不会: 所以总 ...

  4. css3 画半圆和1/4圆

    半圆: #circle1 { width: 100px; height: 200px; background-color: #a72525; -webkit-border-radius: 100px ...

  5. grafana 安装 和 Nginx 、EL 联调

    https://blog.csdn.net/u010735147/article/details/80943593

  6. 牛客练习赛1 矩阵 字符串二维hash+二分

    题目 https://ac.nowcoder.com/acm/contest/2?&headNav=www#question 解析 我们对矩阵进行二维hash,所以每个子矩阵都有一个额hash ...

  7. android Containers控件

    1.RadioGroup 一组单选框容器 2.ListView 3.GridView 4.ExpandableListView 可折叠列表 5.ScrollView 上下滚动条 6.Horizonta ...

  8. vue搭建cli脚手架环境(出现问题及解决,主要是node版本低)

    Vue 提供了一个官方的cli,为单页面应用 (SPA) 快速搭建繁杂的脚手架. 一.vue cli脚手架 脚手架通过webpack搭建开发环境 使用ES6语法 打包压缩js为一个文件 项目文件在环境 ...

  9. Java运算基础

    计算机对负数的运算 =  先取绝对值的原码----> 然后取反,----->+1   这是负数的补码表示 例如  -5       5的原码= 0000,0101  取反   1111,1 ...

  10. python入门示例程序

    该实例是raspi和dsp电机运动控制板的串口uart通信: import serial class SerialHandler(): ''' raspi serial for communicati ...