可重入锁和不可重入锁概念和区别(顺便介绍一下ReentrantLock和ReentrantReadWriteLock)

文章转载自:https://blog.csdn.net/u013452335/article/details/86576939

概念

可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得该锁。

这种情景,可以是不同的线程分别调用这个两个方法。也可是同一个线程,A方法中调用B方法,这个线程调用A方法。

不可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得不了该锁,必须等A方法释放掉这个锁。

可重入锁

在java 中,synchronized和java.util.concurrent.locks.ReentrantLock是可重入锁。
问:当一个线程获得当前实例的锁lock,并且进入了方法A,该线程在方法A没有释放该锁的时候,是否可以再次进入使用该锁的方法B?
答:不可重入锁:在方法A释放锁之前,不可以再次进入方法B 可重入锁:在方法A释放该锁之前可以再次进入方法B

测试:

public class Lock {

    private boolean isLock = false;

    public void lock() throws InterruptedException{
        while(isLock){
            wait();
        }

        isLock = true;
    }

    public void unLock(){
        isLock = false;
    }

}
/**
 * 可重入锁
 */
public class RennerLock {

    private boolean isLock = false;

    Thread thread = null;

    public void lock() throws InterruptedException{
        Thread currentThread = Thread.currentThread();
        while(isLock && thread != currentThread){
            wait();
        }

        isLock = true;
        thread = currentThread;
    }

    public void unLock(){
        isLock = false;
    }
}

测试

public class Test {

    RennerLock lock = new RennerLock();
//    Lock lock = new Lock();

    void read()throws InterruptedException{
        lock.lock();
        System.out.println("read...");
        read1();
        lock.unLock();
    }

    private void read1() throws InterruptedException {
        lock.lock();
        System.out.println("read1...");
        lock.unLock();
    }

    public static void main(String[] args) {

        try {
            new Test().read();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。ReentrantLock和synchronized都是可重入锁

synchronized:因为是自动加锁解锁,所以也注意不到这个说法(也就是嵌套的话,也不会死锁)
ReentrantLock:下面代码

private static final Lock lock = new ReentrantLock();// 非公平的,有参的是可以相对公平的

    public static void needLock(){
        try {
            lock.lock();
            TimeUnit.SECONDS.sleep(1);
            methodB();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }


    }

    private static void methodB() {
        try {
            lock.lock();
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    public static void main(String[] args) {
        needLock();
    }

参考:https://www.jianshu.com/p/4b45f9a1f7d2

ReentrantLock是互斥排他锁,同一时间只能有一个线程在执行任务,ReentrantLock支持锁的重入功能,虽然保证了线程的安全性,但是效率不高,实际上应该是写操作互斥,读操作共享。而jdk提供了读写锁ReentrantReadWriteLock

这里只展示读写互斥

static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public static void read() {
        try {
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + " start");
            Thread.sleep(10000);
            System.out.println(Thread.currentThread().getName() + " end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }

    public static void write() {
        try {
            lock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + " start");
            Thread.sleep(10000);
            System.out.println(Thread.currentThread().getName() + " end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                read();
            }
        });
        t1.setName("t1");

        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                write();
            }
        });
        t2.setName("t2");

        t1.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t2.start();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值