可重入锁与不可重入锁之间的区别与性能差异?

本文深入探讨了可重入锁的概念,通过实例演示了synchronized和ReentrantLock如何实现线程内的锁重入,避免死锁。同时,对比分析了不可重入锁的实现方式,包括synchronized wait notify和CAS+自旋。

可重入锁

指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁
为了避免死锁的发生,JDK中基本都是可重入锁

下面我们来测试一下synchronized和 java.util.concurrent.lock.ReentrantLock 锁的可重入性


测试synchronized加锁可重入性

class TestSychronizedReentrant{
    public static void main(String[] args) {
        new Thread(new SychronizedReentrant()).start();
    }
}
class SychronizedReentrant implements Runnable{
    private Object object = new Object();
    /**
     * 方法一调用方法二
     */
    public void method1(){
        synchronized (object){
            System.out.println(Thread.currentThread().getName()+ " method1 ");
            method2();
        }
    }
    
    /**
        方法二,打印获取obj锁
        如果是同一线程,锁不可以重入,method2需要等待method1释放锁
         */
    public void method2(){
        
        synchronized (object){
            System.out.println(Thread.currentThread().getName()+ " method2 ");
        }
    }

    @Override
    public void run() {
        method1();
    }
}

Thread-0 method1
Thread-0 method2


测试ReentrantLock的可重入性

class TestLockReentrant{
    public static void main(String[] args) {
        new Thread(new LockReentrant()).start();
    }
}
class LockReentrant implements Runnable{
    private final Lock lock = new ReentrantLock();
    /**
     * 方法一:调用方法二
     */
    public void method1(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "method1");
            method2();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 打印获取object锁
     */
    public void method2(){
        lock.lock();//获取锁
        try {
            System.out.println(Thread.currentThread().getName() + "method2");

        }finally {
            lock.unlock();
        }
    }

    @Override
    public void run() {
        //线程启动,调用方法1
        method1();
    }
}

Thread-0method1
Thread-0method2

我们发现方法二都能获取到锁,所以说他们都是可重入锁


测试不可重入锁

我们在JDK中并没有找到可重入锁,所以可以考虑自己实现.有两种实现方式:通过synchronized和wait notify实现;通过CAS+自旋方式实现


synchronized wait notify 方式实现

public class NonReentrantLockBywait {
    //是否被锁
    private volatile boolean locked = false;
    //加锁
    public synchronized void lock(){
        while (locked){
            try {
                wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //加锁成功 locked设置为true
        locked = true;
    }
    //释放锁
    public synchronized void unLock(){
        locked = false;
        notify();
    }
}

通过CAS + 自旋方式实现

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);
    }
}

测试类

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();
        }
    }

    @Override
    public void run() {
        //线程启动 执行方法1
        method1();
    }
}

测试结果都是在method1,调用method2的时候,导致了死锁,线程一直等待或者自旋下去

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值