ReentrantLock(重入锁)使用方式

ReentrantLock(重入锁)使用方式

心血来潮研究一下 BlockingQueue的实现原理,发现ArrayBlockingQueue的源码实现中应用到了ReentrantLock(重入锁)。
因此这里做一些简单记录。

ReentrantLock

ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义。

  • 但其添加了类似轮询锁、定时锁等候可中断锁等候的一些特性。

Reentrant ,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1;然后锁需要被释放两次才能获得真正释放。
这模仿了 synchronized 的语义,如果线程进入由线程已经拥有的监控器保护的 synchronized 块,就允许线程继续进行,当线程退出第二个(或者后续) synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized 块时,才释放锁。

如何使用

ReentrantLock takeLock = new ReentrantLock();  
// 获取锁  
takeLock.lock();  
try {  
  // 代码块  
} finally {  
  // 释放锁 (lock 必须在 finally 块中释放)
  takeLock.unlock();  
}  

注:
lock 必须在 finally 块中释放

举个例子


public class ReentrantLockTest {

    public static void main(String[] args) {
        //
        final Test tt = new Test();
        //
        new Thread("Thread_1") {
            @Override
            public void run() {
                System.out.println("---Thread_1 run begin---");
                tt.await();
                System.out.println("---Thread_1 run end---");
            }
        }.start();
        //
        new Thread("Thread_2") {
            @Override
            public void run() {
                System.out.println("---Thread_2 run begin---");
                tt.signal();
                System.out.println("---Thread_2 run end---");
            }
        }.start();
    }

    public static class Test {
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();

        public void await() {
            System.out.println(" ---Test.await---begin " + Thread.currentThread().getName());
            try {
                // 获取锁
                lock.lock();
                System.out.println("Test.await: lock.lock() " + Thread.currentThread().getName());
                // 进入等待状态,进入等待状态后,其他线程可以获取锁
                System.out.println("Test.await: condition.await() " + Thread.currentThread().getName());
                condition.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                lock.unlock();
                System.out.println("Test.await: lock.unlock() " + Thread.currentThread().getName());
            }
            System.out.println(" ---Test.await---end " + Thread.currentThread().getName());
        }

        public void signal() {
            System.out.println(" ---Test.signal---begin " + Thread.currentThread().getName());
            try {
                // 获取锁
                lock.lock();
                System.out.println("Test.signal: lock.lock() " + Thread.currentThread().getName());
                // 唤醒等待线程
                System.out.println("Test.signal: condition.signal() " + Thread.currentThread().getName());
                condition.signal();
                Thread.sleep(5000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                lock.unlock();
                System.out.println("Test.signal: lock.unlock() " + Thread.currentThread().getName());
            }
            System.out.println(" ---Test.signal---end " + Thread.currentThread().getName());
        }
    }
}

执行结果:

---Thread_1 run begin---
 ---Test.await---begin Thread_1
Test.await: lock.lock() Thread_1 // Thread_1获取锁
Test.await: condition.await() Thread_1 // 执行condition.await()后,其他线程可获取锁 
---Thread_2 run begin---
 ---Test.signal---begin Thread_2
Test.signal: lock.lock() Thread_2 // Thread_2获取锁
Test.signal: condition.signal() Thread_2 // 执行condition.signal()后,唤醒之前的condition.await()线程
// Thread_2 进入5000ms等待状态...
Test.signal: lock.unlock() Thread_2 // Thread_2释放锁
Test.await: lock.unlock() Thread_1 // Thread_1被唤醒
 ---Test.await---end Thread_1
 ---Test.signal---end Thread_2
---Thread_2 run end---
---Thread_1 run end---

这里边有一点要注意:

如果某个线程调用condition.await()进入等待状态,其他线程是可以获取到ReentrantLock锁的。

这不公平

ReentrantLock 构造方法的一个参数是 boolean fair,它允许开发者选择想要一个 公平(fair)锁,还是一个 不公平(unfair)锁

  • 公平锁使线程按照请求锁的顺序依次获得锁;
  • 而不公平锁则允许直接获取锁,在这种情况下,线程有时可以比先请求锁的其他线程先得到锁。
/**
 * Creates an instance of {@code ReentrantLock} with the
 * given fairness policy.
 *
 * @param fair {@code true} if this lock should use a fair ordering policy
 */
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

参考:

synchronized 与 ReentrantLock 对比

轻松学习java可重入锁(ReentrantLock)的实现原理

========== THE END ==========

你可能感兴趣的:(Java,Java源码)