Java锁机制

读写锁

读写锁原理

读写锁是解决 读多写少 场景的并发控制机制

并发环境下,当多个线程同时读取共享数据时,使用读写锁可以允许多个线程过去读锁,提高读锁效率;

当某线程需要更新共享数据时,需要获取写锁,此时所有读线程和写线程都被阻塞,保证数据的一致性;

读写锁实现

Java 通过 ReentrantReadWriteLock 类实现读写锁。

当没有线程持有写锁时,多个线程可以同时持有读锁,从而允许并发读取操作;

当一个线程持有写锁时,其他线程无法持有读锁和写锁,从而保证写操作的互斥性;

三大特性:
  • 公平性:支持公平和非公平两种模式。
  • 重入性:支持重入,读写锁都支持最多65535个。
  • 锁降级:先获取写锁,再获取读锁,再释放写锁,写锁就能降级为读锁。

读写锁的过程

实现过程:
  1. 获取读锁(ReadLock):
    • 通过调用 readLock() 方法获取读锁示例
    • 当线程持有读锁时,其他线程可以同时持有读锁,允许并发读取操作
    • 如果其他线程持有写锁,则读取读锁线程会被阻塞,知道写锁被释放(保证写锁操作的原子性和一致性)
  2. 获取写锁(WriteLock):
    • 通过 writeLock() 方法获取读写锁示例
    • 写锁是占有锁,同一时刻只有一个线程持有写锁
    • 如果其他线程持有读锁或写锁时,则获取写锁的线程会被阻塞,直到所有读锁和写锁被释放
  3. 释放锁
    • 无论读锁还是写锁,在完成操作后都应该调用 unlock() 方法释放锁,以便其他线程可以获取锁
  4. 重入性
    • ReentrantReadWriteLock 支持锁的重入性,即同一个线程可以多次获取同一种类型的锁而不会造成死锁
    • 常见场景:token缓存没有刷新机制,只能在读取使用过程,发现过期后刷新并重新读取,此时还是同线程
代码示例:
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWriteLockExample {
    private static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private static ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private static ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    private static int sharedData = 0;

    public static void main(String[] args) {
        // 获取读锁并进行读操作
        readLock.lock();
        try {
            // 读取共享数据
            System.out.println("Reading data: " + sharedData);
        } finally {
            readLock.unlock();
        }

        // 获取写锁并进行写操作
        writeLock.lock();
        try {
            // 修改共享数据
            sharedData = 42;
            System.out.println("Writing data: " + sharedData);
        } finally {
            writeLock.unlock();
        }
    }
}

特殊场景(锁降级)

锁降级指的是一个持有写锁降级为读锁的过程。帮助减少锁的持有时间,提高并发性能,并且避免潜在的死锁情况

实现过程:
  1. 获取写锁
  2. 对共享资源进行读写操作
  3. 线程先获取读锁,再释放写锁
  4. 释放写锁(此时线程依然持有读锁)

锁降级是依赖读锁的共享特性,多个线程可以同时持有读锁;锁升级是不被允许的,因为读锁共享,写锁却仅能存在一个

代码示例:
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockDowngradingExample {
    private static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private static ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    private static ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private static int sharedData = 0;

    public static void main(String[] args) {
        // 获取写锁
        writeLock.lock();
        try {
            // 操作共享资源
            sharedData = 42;
            System.out.println("Writing data: " + sharedData);

            // 锁降级
            readLock.lock();
        } finally {
            // 释放写锁
            writeLock.unlock();
        }

        try {
            // 继续读取共享资源
            System.out.println("Reading data: " + sharedData);
        } finally {
            // 释放读锁
            readLock.unlock();
        }
    }
}

源码解析ReentrantReadWriteLock读写锁解析-腾讯云开发者社区-腾讯云 (tencent.com)

遇到的问题:当一个线程获取写锁时,仅是会将其余线程动作拦在 “门外”,但写锁操作完成释放后,其余线程岂不是还是会继续写锁吗?

死锁

待拓展…

当知识遇见实践,智慧得以升华

就像此次实现 token 缓存机制,恰好可以借助 Java 锁机制来提升系统性能和数据安全性

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值