import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; /**
* @author admin
* @date 2018/1/16 12:16
* ReentrantLock 可重入锁:
* 1、启动两个线程,线程A获取锁,然后执行;同时线程B进来后,一直阻塞,直到线程A释放锁之后,线程B才接着执行
*/
public class ReentrantLockTest {
ReentrantLock lock = new ReentrantLock(); public void reentrantLockRun1(String threadName) {
System.out.println(threadName + "进入");
lock.lock();
System.out.println(threadName + "方法被锁");
try {
System.out.println(threadName + "方法执行");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(threadName + "锁被释放");
}
} public static void main(String[] args) {
ReentrantLockTest rltest = new ReentrantLockTest();
Thread thread = new Thread() {
public void run() {
rltest.reentrantLockRun1("线程A");
}
};
thread.start(); Thread thread2 = new Thread() {
public void run() {
rltest.reentrantLockRun1("线程B");
}
};
thread2.start();
}
} 运行结果:
线程A进入
线程A方法被锁
线程A方法执行
线程B进入
线程A锁被释放
线程B方法被锁
线程B方法执行
线程B锁被释放
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; /**
* @author admin
* @date 2018/1/16 12:16
* ReentrantLock 可重入锁:
* 1、启动两个线程,线程A获取锁,然后执行,不释放锁,接着线程A再调用reentrantLockRun2,不需要阻塞,接着执行,最后释放锁;说明同一个线程对ReentrantLock可重复获取
* 2、线程B在这个过程中一直阻塞,等到线程A把所有的锁释放完之后,再获取锁,执行方法,最后释放锁
*/
public class ReentrantLockTest2 {
ReentrantLock lock = new ReentrantLock(); public ReentrantLock reentrantLockRun1(String threadName) {
System.out.println(threadName + "进入");
lock.lock();
System.out.println(threadName + "方法被锁");
try {
System.out.println(threadName + "方法执行");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return lock;
} public ReentrantLock reentrantLockRun2(String threadName) {
System.out.println(threadName + "进入");
lock.lock();
System.out.println(threadName + "方法被锁");
try {
System.out.println(threadName + "方法执行");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return lock;
} public static void main(String[] args) {
ReentrantLockTest2 rltest = new ReentrantLockTest2();
Thread thread = new Thread() {
public void run() {
ReentrantLock lock1 = rltest.reentrantLockRun1("线程A");
ReentrantLock lock2 = rltest.reentrantLockRun2("线程A2");
lock1.unlock();
System.out.println("线程A释放锁");
lock2.unlock();
System.out.println("线程A2释放锁"); }
};
thread.start(); Thread thread2 = new Thread() {
public void run() {
ReentrantLock lock = rltest.reentrantLockRun1("线程B");
lock.unlock();
System.out.println("线程B释放锁"); }
};
thread2.start();
}
} 运行结果:
线程A进入
线程A方法被锁
线程A方法执行
线程B进入
线程A2进入
线程A2方法被锁
线程A2方法执行
线程A释放锁
线程A2释放锁
线程B方法被锁
线程B方法执行
线程B释放锁

根据源码发现:维护了这个可见性变量state ;同一个线程对可重入锁体现用state标记作累加,int nextc = c + acquires;

private volatile int state;

public void lock() {
sync.lock();
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
} // 判断是不是第一次获取锁,如果是操作state=1;否则判断是不是同一个线程如果是state+1,如果不是同一个线程直接返回false
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
// 大概就是用一个链表来维护等待线程
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
 

ReentrantLock可重入锁的理解和源码简单分析的更多相关文章

  1. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  2. ReenTrantLock可重入锁和synchronized的区别

    ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...

  3. JUC 一 ReentrantLock 可重入锁

    java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...

  4. ReentrantLock——可重入锁的实现原理

    一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...

  5. java ReentrantLock可重入锁功能

    1.可重入锁是可以中断的,如果发生了死锁,可以中断程序 //如下程序出现死锁,不去kill jvm无法解决死锁 public class Uninterruptible { public static ...

  6. 40 多线程(十二)——ReentrantLock 可重入锁

    我们使用的synchronized加的锁是可以延续使用的,如下: public void test() { //第一次获得锁 synchronized(this) { while(true) { // ...

  7. ReentrantLock可重入锁、公平锁非公平锁区别与实现原理

    ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...

  8. ReentrantLock可重入锁——源码详解

    开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...

  9. ReentrantLock可重入锁的使用场景(转)

    摘要 从使用场景的角度出发来介绍对ReentrantLock的使用,相对来说容易理解一些. 场景1:如果发现该操作已经在执行中则不再执行(有状态执行) a.用在定时任务时,如果任务执行时间可能超过下次 ...

随机推荐

  1. PAT Basic 1046

    1046 划拳 (15 分) 划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字.如果谁比划出的数字正好等于两人喊出的数字之和,谁就赢了,输 ...

  2. 命令行添加subl命令

    添加了此命令后可以使用subl加文件或路径,就能通过命令行使用sublime text打开相应的文件或目录. 这里我的是MacOS,windows系统换路径就好. 第一步 sudo ln -s /Ap ...

  3. GMA Round 1 大吉大利,晚上吃鸡

    传送门 大吉大利,晚上吃鸡 新年走亲访友能干点啥呢,咱开黑吃鸡吧. 这里有32个人,每个人都可能想玩或者不想玩,这样子一共有$2^{32}$种可能.而要开黑当然得4人4人组一队(四人模式),所以说如果 ...

  4. 利用百度OCR实现验证码自动识别

    在爬取网站的时候都遇到过验证码,那么我们有什么方法让程序自动的识别验证码呢?其实网上已有很多打码平台,但是这些都是需要money.但对于仅仅爬取点数据而接入打码平台实属浪费.所以百度免费ocr正好可以 ...

  5. C# RabbitMQ优先级队列实战项目演练

    一.需求背景 当用户在商城上进行下单支付,针对客户等级的不同和订单金额的大小划分客户级别,需要优先处理给标识为大订单的客户发送一份订单邮件提醒.那么我们应用程序如何解决这样的需求场景呢?今天阿笨给大家 ...

  6. [CentOS7]安装tomcat并开启自启动

    安装jdk 1.CentOS 6.X 和 7.X 自带有OpenJDK runtime environment (openjdk).它是一个在linux上实现开源的Java 平台. yum searc ...

  7. JSON序列——保存修改数据2

    JSON序列——保存修改数据2 procedure TForm1.Button7Click(Sender: TObject); begin var delta: TynJsonDelta := Tyn ...

  8. 更新 app 操作过期提示

    增加的操作过期提示,再让用户选择是否登录,登录成功后自动返回上一次操作的面页

  9. oracle去掉字段全部空格进行模糊查询

    sql如下: select * from pwlp_law_person where replace(name,' ','') like replace('吕 刚',' ','');

  10. ninja-build环境安装

    ninja是一个小型构建系统,专注于速度,和常用的make类似,有一些软件就是基于ninja编译构建的,比如clickhouse数据库就需要依赖ninja,因为最近在研究clickhouse,需要依赖 ...