java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java ReentrantLock

Java ReentrantLock的可重入性与公平锁机制详解

作者:晔子yy

这篇文章主要介绍了Java ReentrantLock的可重入性与公平锁机制,Java中的ReentrantLock是一个可重入的互斥锁,基于AQS实现,它允许同一线程多次获取同一把锁,并控制加锁与释放,支持公平/非公平策略及tryLock等灵活特性,需要的朋友可以参考下

1.ReentrantLock介绍

ReentrantLock​ 是Java 并发包(java.util.concurrent.locks)中提供的一个可重入互斥锁,功能类似于synchronized关键字,但提供了更灵活的锁控制机制。

2.ReentrantLock核心特性

2.1可重入性

同一个线程可以多次获取同一把锁,而不会产生死锁

ReentrantLock lock = new ReentrantLock();
public void func1() {
    lock.lock();
    try {
        inner();
    } finally {
        lock.unlock();
    }
}
public void func2() {
    lock.lock();  // 同一个线程可以再次获取锁
    try {
        // 操作
    } finally {
        lock.unlock();
    }
}

2.2公平性选择

支持公平锁和非公平锁两种模式

默认使用非公平锁,非公平锁和公平锁的区别在于公平锁多了判断在等待队列中是否已经有线程在排队的条件。

// 非公平锁
ReentrantLock unfairLock = new ReentrantLock();
// 公平锁
ReentrantLock fairLock = new ReentrantLock(true);

2.3中断响应

支持在等待锁的过程中响应中断

使用lock.lockInterruptibly()即可设置可中断的获取锁

public void method() throws InterruptedException {
    lock.lockInterruptibly();  // 可中断的获取锁
    try {
        // 操作
    } finally {
        lock.unlock();
    }
}

2.4超时机制

3.ReentrantLock基本使用方法

我们来模拟一个简单的多线程环境下对单一共享变量做更改的场景

public class Counter {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;
    public void increment() {
        lock.lock();  // 获取锁
        try {
            count++;
        } finally {
            lock.unlock();  // 必须放在finally中确保释放
        }
    }
}

和sychronized类似,其本质都是将需保证线程安全的变量放到代码块中,使用锁将代码块包裹。不一样的点在于Reentrantlock需要手动释放锁,为了保证每次使用锁后安全地释放,我们使用finally关键字去实现锁的释放。

4.ReentrantLock和sychronized对比

synchronized和ReentrantLock都是Java 中提供的可重入锁,但却有着较多的不同点

ReentrantLock与synchronized对比

ReentrantLocksynchronized
实现方式Java代码实现JVM内置(C/C++)
锁获取方式手动 lock()/unlock()自动获取/释放
可中断性lockInterruptibly()不支持
超时机制tryLock()不支持
公平锁支持不支持
性能优化AQS+CAS锁升级

虽说在性能上二者相差无几,但是ReentrantLock提供了更多可选的功能,灵活性要比传统synchronized锁要更高,所以在大部分场景中,我们会选择使用ReentrantLock作为第一选择,而synchronized因为其有着自动获取和释放锁的优势,在简单的业务场景中会经常看见它的身影。

5.ReentrantLock使用主要事项

5.1锁的释放

由于ReentrantLock没有提供自动获取和释放锁,所以在每次使用完后必须手动释放

lock.lock();
try {
    // 临界区代码
} finally {
    lock.unlock();
}

5.2锁的层级嵌套

虽然ReentrantLock支持可重入锁,但是随着嵌套层级增加,代码可读性会大大下降

//嵌套层次过深
public void methodA() {
    lock.lock();
    try {
        methodB();
    } finally {
        lock.unlock();
    }
}
public void methodB() {
    lock.lock();  // 再次获取
    try {
        // ...
    } finally {
        lock.unlock();
    }
}

以上就是Java ReentrantLock的可重入性与公平锁机制详解的详细内容,更多关于Java ReentrantLock的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文