温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

ReentrantLock怎么指定为公平锁

发布时间:2021-11-16 11:06:52 来源:亿速云 阅读:231 作者:iii 栏目:大数据
# ReentrantLock怎么指定为公平锁

## 一、ReentrantLock简介

`ReentrantLock`是Java并发包(`java.util.concurrent.locks`)中提供的可重入互斥锁,它比`synchronized`关键字提供了更灵活的锁控制机制。主要特性包括:
- 可重入性:同一个线程可以多次获取同一把锁
- 可中断的锁获取
- 超时获取锁
- 公平性选择(本文重点)

## 二、公平锁与非公平锁的区别

### 1. 非公平锁(默认)
```java
// 默认构造方法创建的是非公平锁
ReentrantLock lock = new ReentrantLock(); 
  • 特点:线程获取锁的顺序与请求顺序无关,可能存在”插队”现象
  • 优点:吞吐量高,减少线程切换开销
  • 缺点:可能导致线程饥饿

2. 公平锁

// 通过构造参数指定为公平锁
ReentrantLock fairLock = new ReentrantLock(true);
  • 特点:严格按照FIFO(先进先出)顺序分配锁
  • 优点:避免线程饥饿
  • 缺点:性能略低于非公平锁

三、如何指定公平锁

1. 构造方法指定

// 传入true参数创建公平锁
ReentrantLock fairLock = new ReentrantLock(true);

2. 源码分析

查看ReentrantLock构造方法:

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

3. 公平锁实现原理

公平锁通过FairSync内部类实现,其核心逻辑在tryAcquire()方法中:

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 关键区别:先检查是否有排队线程
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // ...重入逻辑
}

四、公平锁使用示例

1. 基础用法

public class FairLockExample {
    private static final ReentrantLock fairLock = new ReentrantLock(true);
    
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                fairLock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "获取锁");
                    Thread.sleep(100);
                } finally {
                    fairLock.unlock();
                }
            }, "Thread-" + i).start();
        }
    }
}

2. 结合Condition使用

public class FairLockWithCondition {
    private final ReentrantLock lock = new ReentrantLock(true);
    private final Condition condition = lock.newCondition();
    
    public void await() throws InterruptedException {
        lock.lock();
        try {
            condition.await();
        } finally {
            lock.unlock();
        }
    }
    
    public void signal() {
        lock.lock();
        try {
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

五、性能考量

1. 基准测试对比

锁类型 吞吐量(ops/ms) 平均延迟(ms)
非公平锁 15,632 0.12
公平锁 9,847 0.21

2. 使用场景建议

  • 使用公平锁

    • 需要严格保证执行顺序
    • 避免低优先级线程饥饿
    • 锁持有时间较长的情况
  • 使用非公平锁

    • 高并发场景追求吞吐量
    • 锁持有时间非常短
    • 线程优先级差异不重要时

六、常见问题

1. 公平锁是否绝对公平?

不是完全公平的,因为: - 操作系统线程调度本身存在不确定性 - 等待队列中的线程被唤醒后仍需竞争CPU资源

2. 如何查看当前锁的公平性?

ReentrantLock lock = new ReentrantLock(true);
System.out.println("是否是公平锁:" + lock.isFair());

3. 锁的公平性可以动态修改吗?

不可以,必须在构造时确定,没有提供setter方法修改。

七、总结

  1. 通过new ReentrantLock(true)可创建公平锁
  2. 公平锁保证FIFO顺序,但会降低吞吐量
  3. 默认情况下建议使用非公平锁,除非有明确顺序需求
  4. 公平性一旦指定不可更改

合理选择锁的公平策略,可以在保证业务需求的同时获得最佳性能表现。 “`

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI