ReentrantLock可重入锁的理解和源码简单分析
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可重入锁的理解和源码简单分析的更多相关文章
- ReenTrantLock可重入锁(和synchronized的区别)总结
ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...
- ReenTrantLock可重入锁和synchronized的区别
ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...
- JUC 一 ReentrantLock 可重入锁
java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...
- ReentrantLock——可重入锁的实现原理
一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...
- java ReentrantLock可重入锁功能
1.可重入锁是可以中断的,如果发生了死锁,可以中断程序 //如下程序出现死锁,不去kill jvm无法解决死锁 public class Uninterruptible { public static ...
- 40 多线程(十二)——ReentrantLock 可重入锁
我们使用的synchronized加的锁是可以延续使用的,如下: public void test() { //第一次获得锁 synchronized(this) { while(true) { // ...
- ReentrantLock可重入锁、公平锁非公平锁区别与实现原理
ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...
- ReentrantLock可重入锁——源码详解
开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...
- ReentrantLock可重入锁的使用场景(转)
摘要 从使用场景的角度出发来介绍对ReentrantLock的使用,相对来说容易理解一些. 场景1:如果发现该操作已经在执行中则不再执行(有状态执行) a.用在定时任务时,如果任务执行时间可能超过下次 ...
随机推荐
- 如何修改PHP的memory_limit限制
在运行PHP程序,通常会遇到“Fatal Error: Allowed memory size of xx bytes exhausted”(允许内存大小为 xx 字节耗尽)的错误, 这个意味着PHP ...
- java-----任意进制间的转换
public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Sy ...
- Egret引擎的常用倒计时
直接上代码, private timeControl() { let timer: egret.Timer = segret.Timer(); timer.addEventListener(egret ...
- python 计算程序运行耗时的好用的代码
python 计算程序运行耗时的好用的代码: import time start=time.clock() sum=0 for i in range(50): sum=sum+i print(sum) ...
- weblogic 下异常 org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken
项目之前在 Tomcat 环境下一直都正常运行,今天应客户要求需要迁移到 webLogic 10.3.6 下, 部署后竟然抛出了 org.hibernate.QueryException: Class ...
- 修正mui的上拉加载和下拉刷新的一次未完成就执行下一次的请求
有的用户会在第一次 上拉和下拉 事件未完成的时候,就执行第二次,第三次请求.... 提示文字也加上的位置动态计算,修改了mui的部份源码实现,我们的需求达到了 我们来看一下 腾讯新闻 的效果:
- 每天一个linux命令:du
1.命令简介 du (Disk usage) 用来计算每个文件的磁盘用量,目录则取总用量. 2.用法 用法:du [选项]... [文件]... 或:du [选项]... --files0-from= ...
- 【Linux】使用Google Authenticator 实现ssh登录双因素认证
一般来说,使用ssh远程登录服务器,只需要输入账号和密码,显然这种方式不是很安全.为了安全着想,可以使用GoogleAuthenticator(谷歌身份验证器),以便在账号和密码之间再增加一个验证码, ...
- Swift实时画箭头的实现
iOS上实现画箭头,如果是指定了坐标点,那是很简单的,但如果需要做到实时绘制,就需要计算一下了 需求: 在白板上,根据手势落下点和移动点,实时绘制一条箭头直线(如下图) 实现代码: /// 获取箭头的 ...
- 使用 Docker 镜像构建 GO 语言环境
1. 安装 Docker 我当前使用的系统环境是 CentOS7 ,安装 Docker 使用的命令是 yum install docker*.至于其它系统,可以到百度查找其对应的安装方式. 2. 配置 ...