面试题: 你了解 Java 中的读写锁吗?

是的,Java 中的读写锁是一种特殊的锁机制,允许多个线程同时读取共享资源,但在写操作时需要独占锁。这种机制可以提高并发性能,特别是在读多写少的场景中。

Java 提供了 ReentrantReadWriteLock 类来实现读写锁。以下是读写锁的核心概念和使用方法:


1. 读写锁的核心概念

  • 读锁(共享锁)
    • 多个线程可以同时持有读锁。
    • 读锁之间不会互斥,允许多个线程同时读取共享资源。
  • 写锁(独占锁)
    • 写锁是独占的,同一时刻只能有一个线程持有写锁。
    • 写锁与读锁互斥,写锁会阻塞所有读锁和其他写锁。

2. 读写锁的使用

ReentrantReadWriteLock 提供了两个锁对象:

  • readLock():获取读锁。
  • writeLock():获取写锁。

示例:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private int sharedData = 0;

    public void readData() {
        rwLock.readLock().lock(); // 获取读锁
        try {
            System.out.println(Thread.currentThread().getName() + " 读取数据: " + sharedData);
        } finally {
            rwLock.readLock().unlock(); // 释放读锁
        }
    }

    public void writeData(int data) {
        rwLock.writeLock().lock(); // 获取写锁
        try {
            sharedData = data;
            System.out.println(Thread.currentThread().getName() + " 写入数据: " + data);
        } finally {
            rwLock.writeLock().unlock(); // 释放写锁
        }
    }

    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();

        // 创建多个读线程
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                example.readData();
            }, "读线程-" + i).start();
        }

        // 创建多个写线程
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                example.writeData((int) (Math.random() * 100));
            }, "写线程-" + i).start();
        }
    }
}

3. 读写锁的特性

  • 公平性
    • ReentrantReadWriteLock 支持公平模式和非公平模式。
    • 在公平模式下,锁的获取按照请求的顺序进行。
    • 在非公平模式下,锁的获取可能会插队,提高吞吐量。
  • 可重入性
    • 读写锁是可重入的,同一个线程可以多次获取读锁或写锁。
  • 锁降级
    • 写锁可以降级为读锁,但读锁不能升级为写锁。

4. 读写锁的适用场景

  • 读多写少
    • 当读操作远多于写操作时,读写锁可以显著提高性能。
  • 数据一致性要求高
    • 写操作需要独占锁,保证数据的一致性。
  • 缓存系统
    • 缓存数据的读取频率高,更新频率低,适合使用读写锁。

5. 读写锁的注意事项

  • 死锁风险
    • 如果线程在持有读锁的情况下尝试获取写锁,可能会导致死锁。
  • 性能开销
    • 读写锁的实现比普通锁复杂,可能会带来额外的性能开销。

6. 读写锁与普通锁的对比

特性读写锁 (ReentrantReadWriteLock)普通锁 (ReentrantLock)
读操作允许多个线程同时读同一时刻只能有一个线程访问
写操作独占锁,互斥独占锁,互斥
适用场景读多写少读写均衡或写多读少
性能读操作性能高读操作性能较低

总结

  • 读写锁通过分离读锁和写锁,提高了读多写少场景下的并发性能。
  • 使用 ReentrantReadWriteLock 可以实现高效的并发控制。
  • 需要注意死锁风险和性能开销,合理选择锁机制。
THE END
点赞15 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容