原创

java面试题-说一说ReadWriteLock如何使用?

简介

在多线程编程中,读写锁是一种重要的同步机制,用于提高对共享资源的访问效率。Java中的ReentrantReadWriteLockReadWriteLock接口的一种实现,提供了对共享资源进行读写操作的灵活性。

特点

  • 读锁与读锁不互斥
  • 读锁与写锁互斥
  • 支持写锁降级到读锁
  • 无法从读锁升级到写锁
  • 支持中断
  • 写锁支持Condition,读锁不支持Condition

基本使用

首先,我们来看一个简单的示例,根据给定的key获取对应的value。在这个过程中,我们会使用ReentrantReadWriteLock的基本结构。

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

public class ReadWriteLockExample {
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    // 根据 key 获取 value 值
    public Object getValue(String key) {
        lock.readLock().lock(); // 加读锁
        Object value = null;
        try {
            value = cache.get(key);
            if (value == null) {
                lock.readLock().unlock(); // value值为空,释放读锁
                lock.writeLock().lock(); // 加写锁,写入value值
                try {
                    // 重新检查 value值是否已经被其他线程写入
                    if (value == null) {
                        value = "value"; // 写入数据
                    }
                } finally {
                    lock.writeLock().unlock();
                }
                lock.readLock().lock();
            }
        } finally {
            lock.readLock().unlock();
        }
        return value;
    }
}

这个例子展示了如何利用读写锁实现对共享资源的读写操作,确保写入操作不会被多个线程同时执行,而读取操作可以并发进行。

多线程环境下的读写锁使用

下面我们将介绍一个更复杂的例子,展示在多线程环境下如何使用可重入读写锁。我们创建一个包含读写锁的类,用于存储键值对。

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWriteLockDemo {
    // 存储 key value 的 map
    private Map<String, Object> map = new HashMap<>();
    // 读写锁
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    // 根据 key 获取 value
    public Object get(String key) {
        Object value = null;
        lock.readLock().lock();
        try {
            Thread.sleep(50L);
            value = map.get(key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
        return value;
    }

    // 设置 key-value
    public void set(String key, Object value) {
        lock.writeLock().lock();
        try {
            Thread.sleep(50L);
            map.put(key, value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    // 测试5个线程读数据,5个线程写数据
    public static void main(String[] args) {
        // 创建测试可重入读写锁对象
        ReentrantReadWriteLockDemo test = new ReentrantReadWriteLockDemo();
        String key = "lock"; // 存入 map 中的 key
        Random r = new Random(); // 生成随机数作为 value

        // 5 个线程读 map 中 key 的 value
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    System.out.println(Thread.currentThread().getName() + " read value=" + test.get(key));
                }
            }).start();

            // 5 个线程写 map 中 key 的 value
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    int value = r.nextInt(1000);
                    test.set(key, value);
                    System.out.println(Thread.currentThread().getName() + " write value=" + value);
                }
            }).start();
        }
    }
}

这个例子展示了如何在多线程环境下安全地进行读写操作,确保线程安全性。

正文到此结束
本文目录