Java 中可重入锁、不可重入锁的测试
可重入锁
指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁。
为了避免死锁的发生,JDK 中基本都是可重入锁。
下面我们来测试一下 synchronized 和 java.util.concurrent.lock.ReentrantLock 锁的可重入性
测试 synchronized 加锁 可重入性
packageconstxiong.concurrency.a019;/*** 测试 synchronized 加锁 可重入性
*@authorConstXiong
* @date 2019-09-20 15:55:27*/
public classTestSynchronizedReentrant {public static voidmain(String[] args) {new Thread(newSynchronizedReentrant()).start();
}
}class SynchronizedReentrant implementsRunnable {private final Object obj = newObject();/*** 方法1,调用方法2*/
public voidmethod1() {synchronized(obj) {
System.out.println(Thread.currentThread().getName()+ " method1()");
method2();
}
}/*** 方法2,打印前获取 obj 锁
* 如果同一线程,锁不可重入的话,method2 需要等待 method1 释放 obj 锁*/
public voidmethod2() {synchronized(obj) {
System.out.println(Thread.currentThread().getName()+ " method2()");
}
}
@Overridepublic voidrun() {//线程启动 执行方法1
method1();
}
}
打印结果:
Thread-0method1()
Thread-0 method2()
测试 ReentrantLock 的可重入性
packageconstxiong.concurrency.a019;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;/*** 测试 ReentrantLock 的可重入性
*@authorConstXiong
* @date 2019-09-20 16:24:52*/
public classTestLockReentrant {public static voidmain(String[] args) {new Thread(newLockReentrant()).start();
}
}class LockReentrant implementsRunnable {private final Lock lock = newReentrantLock();/*** 方法1,调用方法2*/
public voidmethod1() {
lock.lock();try{
System.out.println(Thread.currentThread().getName()+ " method1()");
method2();
}finally{
lock.unlock();
}
}/*** 方法2,打印前获取 obj 锁
* 如果同一线程,锁不可重入的话,method2 需要等待 method1 释放 obj 锁*/
public voidmethod2() {
lock.lock();try{
System.out.println(Thread.currentThread().getName()+ " method2()");
}finally{
lock.unlock();
}
}
@Overridepublic voidrun() {//线程启动 执行方法1
method1();
}
}
打印结果:
Thread-0method1()
Thread-0 method2()
测试不可重入锁
我在 JDK 中没找到可重入锁,所以考虑自己实现一下。两种方式:通过 synchronized wait notify 实现;通过 CAS + 自旋方式实现
1) synchronized wait notify 方式实现
packageconstxiong.concurrency.a019;/*** 不可重入锁,通过 synchronized wait notify 实现
*@authorConstXiong
* @date 2019-09-20 16:53:34*/
public classNonReentrantLockByWait {//是否被锁
private volatile boolean locked = false;//加锁
public synchronized voidlock() {//当某个线程获取锁成功,其他线程进入等待状态
while(locked) {try{
wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}//加锁成功,locked 设置为 true
locked = true;
}//释放锁
public synchronized voidunlock() {
locked= false;
notify();
}
}
2) 通过 CAS + 自旋 方式实现
packageconstxiong.concurrency.a019;importjava.util.concurrent.atomic.AtomicReference;/*** 不可重入锁,通过 CAS + 自旋 实现
*@authorConstXiong
* @date 2019-09-20 16:53:34*/
public classNonReentrantLockByCAS {private AtomicReference lockedThread = new AtomicReference();public voidlock() {
Thread t=Thread.currentThread();//当 lockedThread 持有引用变量为 null 时,设置 lockedThread 持有引用为 当前线程变量
while (!lockedThread.compareAndSet(null, t)) {//自旋,空循环,等到锁被释放
}
}public voidunlock() {//如果是本线程锁定的,可以成功释放锁
lockedThread.compareAndSet(Thread.currentThread(), null);
}
}
测试类
packageconstxiong.concurrency.a019;/*** 测试不可重入锁
*@authorConstXiong
* @date 2019-09-20 18:08:55*/
public classTestLockNonReentrant{public static voidmain(String[] args) {new Thread(newLockNonReentrant()).start();
}
}class LockNonReentrant implementsRunnable {//private final NonReentrantLockByWait lock = new NonReentrantLockByWait();
private final NonReentrantLockByCAS lock = newNonReentrantLockByCAS();/*** 方法1,调用方法2*/
public voidmethod1() {
lock.lock();try{
System.out.println(Thread.currentThread().getName()+ " method1()");
method2();
}finally{
lock.unlock();
}
}/*** 方法2,打印前获取 obj 锁
* 如果同一线程,锁不可重入的话,method2 需要等待 method1 释放 obj 锁*/
public voidmethod2() {
lock.lock();try{
System.out.println(Thread.currentThread().getName()+ " method2()");
}finally{
lock.unlock();
}
}
@Overridepublic voidrun() {//线程启动 执行方法1
method1();
}
}
测试结果,都是在 method1,调用 method2 的时候,导致了死锁,线程一直等待或者自旋下去。
参考:
Java面试题汇总,总有一道卡住你!
原文:https://www.cnblogs.com/ConstXiong/p/11687815.html