Synchronized和ReentrantLock

2019-02-12  本文已影响4人  ohjam

Synchronized

Synchronized也称内置锁,Java提供同步代码块这种内置的锁机制来支持原子性,同步代码块包括两个部分:一个作为锁的对象引用,一个作为由这个锁保护的代码块。注意synchronized并不是“为这一块代码”加锁,而是给Class对象加锁。

        synchronized (lock) {}

每一个Java对象都能用作实现同步的锁,线程在进入同步代码块之前会自动获得锁,在退出同步代码块时自动释放锁。锁是互斥的,最多只有一个线程能持有这个锁,当A线程持有一个锁,B线程尝试获取这个锁时,B线程只能等待或者阻塞,直到A线程释放这个锁。
内置锁是可重入的,一个线程获取一个由自己持有的锁,这样的请求是成功的。

ReentrantLock

ReentrantLock实现了Lock接口,Lock提供了一种无条件、可轮询、定时、可中断的锁获取操作,加锁和解锁都是显式的。ReentrantLock提供了跟跟内置锁相同的互斥性和内存可见性,提供了相同的可重入的特性。
使用ReentrantLock必须在finally中释放锁,否则如果在代码中抛异常,那这个锁就永远都不能释放。

        // 示例
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
          // ... method body
        } finally {
          lock.unlock();
        }

Synchronized和ReentrantLock的区别

在大多数情况下,内置锁都能很好的完成工作,但是它存在一些局限性,比如,无法中断一个正在等待获取锁的线程。但ReentrantLock也不能完全代替Synchronized,ReentrantLock需要更多的try-catch-finally代码。
在你需要如下特性时,你可以选择使用ReentrantLock来解决你的问题:

public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

马上返回结果和带时间限制的tryLock方法。

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

调用后一直阻塞到获得锁,但是接受中断信号。

可重入的实现原理

重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程,当计数值为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将记下锁的持有者,并且将获取计数值置为1。如果同一个线程再次获取这个锁时,计数值将递增,当线程退出同步代码块时,计数值会递减。当计数值为0时,这个锁将释放。

上一篇 下一篇

猜你喜欢

热点阅读