Java 中可重入锁、不可重入锁的测试
可重入锁
指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁。
为了避免死锁的发生,JDK 中基本都是可重入锁。
下面我们来测试一下 synchronized 和 java.util.concurrent.lock.ReentrantLock 锁的可重入性
- 测试 synchronized 加锁 可重入性
package constxiong.concurrency.a019;/*** 测试 synchronized 加锁 可重入性* @author ConstXiong* @date 2019-09-20 15:55:27*/
public class TestSynchronizedReentrant {public static void main(String[] args) {new Thread(new SynchronizedReentrant()).start();}}class SynchronizedReentrant implements Runnable {private final Object obj = new Object();/*** 方法1,调用方法2*/public void method1() {synchronized (obj) {System.out.println(Thread.currentThread().getName() + " method1()");method2();}}/*** 方法2,打印前获取 obj 锁* 如果同一线程,锁不可重入的话,method2 需要等待 method1 释放 obj 锁*/public void method2() {synchronized (obj) {System.out.println(Thread.currentThread().getName() + " method2()");}}@Overridepublic void run() {//线程启动 执行方法1method1();}}
打印结果:
Thread-0 method1()
Thread-0 method2()
- 测试 ReentrantLock 的可重入性
package constxiong.concurrency.a019;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 测试 ReentrantLock 的可重入性* @author ConstXiong* @date 2019-09-20 16:24:52*/
public class TestLockReentrant {public static void main(String[] args) {new Thread(new LockReentrant()).start();}}class LockReentrant implements Runnable {private final Lock lock = new ReentrantLock();/*** 方法1,调用方法2*/public void method1() {lock.lock();try {System.out.println(Thread.currentThread().getName() + " method1()");method2();} finally {lock.unlock();}}/*** 方法2,打印前获取 obj 锁* 如果同一线程,锁不可重入的话,method2 需要等待 method1 释放 obj 锁*/public void method2() {lock.lock();try {System.out.println(Thread.currentThread().getName() + " method2()");} finally {lock.unlock();}}@Overridepublic void run() {//线程启动 执行方法1method1();}}
打印结果:
Thread-0 method1()
Thread-0 method2()
- 测试不可重入锁
我在 JDK 中没找到可重入锁,所以考虑自己实现一下。两种方式:通过 synchronized wait notify 实现;通过 CAS + 自旋方式实现
1) synchronized wait notify 方式实现
package constxiong.concurrency.a019;/*** 不可重入锁,通过 synchronized wait notify 实现* @author ConstXiong* @date 2019-09-20 16:53:34*/
public class NonReentrantLockByWait {//是否被锁private volatile boolean locked = false;//加锁public synchronized void lock() {//当某个线程获取锁成功,其他线程进入等待状态while (locked) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//加锁成功,locked 设置为 truelocked = true;}//释放锁public synchronized void unlock() {locked = false;notify();}}
2) 通过 CAS + 自旋 方式实现
package constxiong.concurrency.a019;import java.util.concurrent.atomic.AtomicReference;/*** 不可重入锁,通过 CAS + 自旋 实现* @author ConstXiong* @date 2019-09-20 16:53:34*/
public class NonReentrantLockByCAS {private AtomicReference<Thread> lockedThread = new AtomicReference<Thread>();public void lock() {Thread t = Thread.currentThread();//当 lockedThread 持有引用变量为 null 时,设置 lockedThread 持有引用为 当前线程变量while (!lockedThread.compareAndSet(null, t)) {//自旋,空循环,等到锁被释放}}public void unlock() {//如果是本线程锁定的,可以成功释放锁lockedThread.compareAndSet(Thread.currentThread(), null);}
}
测试类
package constxiong.concurrency.a019;/*** 测试不可重入锁* @author ConstXiong* @date 2019-09-20 18:08:55*/
public class TestLockNonReentrant{public static void main(String[] args) {new Thread(new LockNonReentrant()).start();}}class LockNonReentrant implements Runnable {// private final NonReentrantLockByWait lock = new NonReentrantLockByWait();private final NonReentrantLockByCAS lock = new NonReentrantLockByCAS();/*** 方法1,调用方法2*/public void method1() {lock.lock();try {System.out.println(Thread.currentThread().getName() + " method1()");method2();} finally {lock.unlock();}}/*** 方法2,打印前获取 obj 锁* 如果同一线程,锁不可重入的话,method2 需要等待 method1 释放 obj 锁*/public void method2() {lock.lock();try {System.out.println(Thread.currentThread().getName() + " method2()");} finally {lock.unlock();}}@Overridepublic void run() {//线程启动 执行方法1method1();}
}
测试结果,都是在 method1,调用 method2 的时候,导致了死锁,线程一直等待或者自旋下去。
参考:
http://ifeve.com/java_lock_see4/
【Java面试题与答案】整理推荐
- 基础与语法
- 集合
- 网络编程
- 并发编程
- Web
- 安全
- 设计模式
- 框架
- 算法与数据结构
- 异常
- 文件解析与生成
- Linux
- MySQL
- Oracle
- Redis
- Dubbo
Java 中可重入锁、不可重入锁的测试相关推荐
- java中多线程reentlock_Java多线程系列——深入重入锁ReentrantLock
简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为"独占锁". ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychr ...
- 说说Java中原子性,可见性与指令重排序的理解
原子性:就是读数据,处理数据,写数据 这三个步骤不能被终止,或者打断:就是不能被线程调度器中断,切换线程. 这样,才能保证,原子操作在线程切换,并行处理上保证数据地顺序累加处理. 可见性:是Jvm较为 ...
- java中的锁(悲观锁、乐观锁、可重入锁、不可重入锁、公平锁、非公平锁、自旋锁、阻塞锁...)
Lock接口 1.简介.地位.作用 ① 锁是一种工具,用于控制对共享资源的访问 ② Lock和synchronized,这两个是最常见的锁,它们都可以达到线程安全的目的,但是在使用和功能上又有较大的不 ...
- java自适应table_【进阶之路】包罗万象——JAVA中的锁
导言 大家好,我是练习java两年半时间的南橘,下面是我的微信,需要之前的导图或者想互相交流经验的小伙伴可以一起互相交流哦. 在Java中,我们能接触到各种各样的锁,而每种锁因其特性的不同,在不同的的 ...
- 图解Java中那18 把锁
乐观锁和悲观锁 独占锁和共享锁 互斥锁和读写锁 公平锁和非公平锁 可重入锁 自旋锁 分段锁 锁升级(无锁|偏向锁|轻量级锁|重量级锁) 锁优化技术(锁粗化.锁消除) 乐观锁和悲观锁 悲观锁 悲观锁对应 ...
- 图解Java中的18 把锁!
乐观锁和悲观锁 独占锁和共享锁 互斥锁和读写锁 公平锁和非公平锁 可重入锁 自旋锁 分段锁 锁升级(无锁|偏向锁|轻量级锁|重量级锁) 锁优化技术(锁粗化.锁消除) 乐观锁和悲观锁 悲观锁 悲观锁对应 ...
- 一文足以了解什么是 Java 中的锁
作者 | cxuan 责编 | Elle Java 锁分类 Java 中的锁有很多,可以按照不同的功能.种类进行分类,下面是我对 Java 中一些常用锁的分类,包括一些基本的概述 从线程是否需要对资 ...
- 自旋锁和互斥锁的区别 java中lock Syntronized区别
转载自:http://blog.csdn.net/susidian/article/details/51068858 自旋锁(Spin lock) 自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠 ...
- 图解Java中18把锁
乐观锁和悲观锁 独占锁和共享锁 互斥锁和读写锁 公平锁和非公平锁 可重入锁 自旋锁 分段锁 锁升级(无锁|偏向锁|轻量级锁|重量级锁) 锁优化技术(锁粗化.锁消除) 乐观锁和悲观锁 悲观锁 悲观锁对应 ...
- Java 中的锁分类以及锁的原理
锁分类与原理 锁的分类 锁的分类及基本概念 Java对象在内存中的布局: 锁的升级过程: 锁的本质: synchronized 与Lock 的区别: 互斥锁的原理: 1.读写锁 2.读写锁的原理 3. ...
最新文章
- Vue引入百度地图,如何去掉左下角的版权logo百度等信息?
- golang 开发常见坑
- oracle dataguard in-memory,Oracle 11g Dataguard 物理备库配置(一)之Duplicate配置
- 【数据结构与算法】之深入解析“整数反转”的求解思路与算法示例
- POJ - 2083 Fractal(dfs,递归画图)
- 7.2 伪逆和线性方程 $A\mathbf{x}=\mathbf{b}$
- javafx按钮设计风格_Java,JavaFX的流畅设计风格按钮,切换按钮和工具提示
- [html] H5播放的video视频,如何实现对视频截图?
- Vue 模块化开发(构建项目常用工具)
- 【LOJ】#2230. 「BJOI2014」大融合
- c盘python27文件夹可以删除嘛_C盘里的空文件夹是不是都能删除啊
- 使用LibreOffice的Draw取代Microsoft visio
- CSS 字体加粗,导致布局宽度改变怎么处理?
- BootStrap3 排版
- HDMI/DVI 显示器热插拔与检测原理(HPD)
- 磨金石教育摄影技能干货分享|那些酷炫的照片是怎么拍出来的?
- ug创建html文件,UG8.0如何创建和打开中文名称的部件
- 团体程序设计天梯赛--个人总结
- 如何让自己打计算机打字快起来,电脑快速打字的技巧
- 汽车SoC安全故障的自动识别(下):案例展示和指标分析