可重入锁和不可重入锁

14 篇文章 0 订阅

锁就是把代码块、资源或数据(称为临界资源)锁上,访问临界资源的时候只允许一个线程去操作,其他线程必须等待或者放弃,这是为了保证最终程序的正确运行。

不可重入锁

public class Lock {
    private boolean isLocked = false; // 标识锁是否被线程获得

    public synchronized void lock() throws InterruptedException {
        // 如果锁被其他线程获取,则该线程等待
        while(isLocked) {
            wait();
        }

        isLocked = true;
    }

    public synchronized void unlock() {
        isLocked = false;
        notify();
    }
}

使用上面定义的Lock锁:

public class Test{
    public static void main(String[] args) throws InterruptedException {
        Test test = new Test();
        test.print();
    }
    Lock lock = new Lock();

    public void print() throws InterruptedException {
        lock.lock();
        add();
        lock.unlock();
    }

    public void add() throws InterruptedException {
        lock.lock();
        // do something
        lock.unlock();
    }
}

这段程序运行会出现死循环。当调用print()方法的时候,线程获取到锁,然后调用add()方法,线程再次尝试获取锁,被阻塞。add()方法要等print()方法执行结束才能获取锁,而print()方法要等add()方法执行结束才能释放锁,导致死锁。
当调用print()方法时,获得了锁,在未释放锁之前,这个线程就不能再调用其他方法以及在其他方法中尝试获取锁。这种锁称为不可重入锁,也叫自旋锁

可重入锁

public class Lock {
    boolean isLocked = false; // 标识锁是否被线程获得
    Thread lockedBy = null; // 记录获得锁的线程
    int lockedCount = 0; // 记录一个线程中,锁被获取的次数

    public synchronized void lock() throws InterruptedException {
        Thread thread = Thread.currentThread(); // 当前尝试获取锁的线程

        // 锁已经被线程获得,并且获取锁的线程不是当前线程,则当前线程等待
        while(isLocked && lockedBy != thread) {
            wait();
        }

        isLocked = true;
        lockedBy = thread;
        lockedCount++;
    }

    public synchronized void unlock() {
        lockedCount--;

        // 该线程中,获取锁的程序都执行了释放锁操作,线程才真正释放锁
        if(0 == lockedCount) {
            isLocked = false;
            notify();
        }
    }
}

当第一个线程执行print()方法的时候,获取到了锁,lockedBy等于该线程,该线程调用add()方法时,尝试获取锁,isLocked值为true,即锁已经被占用,但是lockedBy等于该线程,所以add()方法可以获取锁,lockedCount的值此时为2。当第二个线程执行print方法的时候,isLocked值为true,并且lockedBy不等于当前线程成立,因此进入等待状态。这就是可重入锁。

可重入锁比不可重入锁多了两个属性:lockedBy表示锁被哪个线程获取,lockedCount表示一个线程内,锁被获取到的次数。根据lockedBy属性,使当前线程的不同代码块可以获取多次锁,根据lockedCount属性,执行真正释放锁的逻辑。

Java中常用的可重入锁

  • synchronized
  • java.util.concurrent.locks.ReentrantLock
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值