MST

星途 面试题库

面试题:Java读写锁实现中的公平性问题

Java中的读写锁(如ReentrantReadWriteLock)在默认情况下是非公平的。请说明公平和非公平策略对于读写锁性能和线程调度的影响,并且如果要实现公平的读写锁,应该如何调整代码?
17.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

公平和非公平策略对读写锁性能和线程调度的影响

  1. 公平策略
    • 线程调度:公平策略下,线程按照请求锁的顺序依次获得锁。即当一个锁可用时,等待时间最长的线程会优先获取锁。这确保了每个线程都有机会获得锁,不会出现某些线程长时间等待的情况,符合“先来先服务”原则。
    • 性能影响:由于需要维护等待线程的顺序,公平策略在高并发场景下会产生额外的开销。每次锁的竞争都需要检查等待队列,这增加了系统的复杂性和上下文切换的次数,从而可能导致整体性能下降。特别是在读操作频繁的场景下,因为读锁可以被多个线程同时持有,公平策略会使得读线程频繁地等待写线程释放锁,降低了读操作的并发性。
  2. 非公平策略
    • 线程调度:非公平策略下,线程获取锁的顺序并不取决于等待时间的长短。当锁可用时,任何一个等待线程都有机会竞争到锁,而不管它等待了多久。这可能导致某些线程长时间等待,出现“饥饿”现象。
    • 性能影响:非公平策略在高并发场景下通常能提供更好的性能。因为它不需要维护等待线程的顺序,减少了锁竞争时的开销。在写操作较少,读操作频繁的情况下,非公平策略允许读线程在写锁释放后立即获取锁,而不需要等待等待队列中的其他线程,提高了系统的整体吞吐量。

实现公平的读写锁

在Java中,ReentrantReadWriteLock默认是非公平的,但可以通过构造函数来创建公平的读写锁。示例代码如下:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class FairReadWriteLockExample {
    private static final ReentrantReadWriteLock fairLock = new ReentrantReadWriteLock(true);
    private static final ReentrantReadWriteLock.ReadLock fairReadLock = fairLock.readLock();
    private static final ReentrantReadWriteLock.WriteLock fairWriteLock = fairLock.writeLock();

    public static void main(String[] args) {
        // 使用公平读写锁进行操作
        fairWriteLock.lock();
        try {
            // 写操作
        } finally {
            fairWriteLock.unlock();
        }

        fairReadLock.lock();
        try {
            // 读操作
        } finally {
            fairReadLock.unlock();
        }
    }
}

在上述代码中,通过new ReentrantReadWriteLock(true)构造函数创建了一个公平的读写锁。true表示采用公平策略,此时线程将按照请求锁的顺序依次获得锁。在实际应用中,可以根据业务场景的需求选择合适的策略,以平衡性能和线程公平性。