【Java JUC】读写自旋锁:共享和独占 —— 基本概念、使用场景和代码示例

概念

读写自旋锁是一种结合了读写锁自旋锁的锁类型,可以同时支持并发读互斥写
Java中可以使用ReentrantReadWriteLock类来实现读写可重入锁,该类提供了读锁和写锁两种类型的锁,都是可重入的。由于读是不对数据造成影响的,读锁是共享的,所以读锁被称为共享锁;由于写操作是对数据的修改,存在线程安全问题,为保证线程安全,写锁是独占的,所以写锁被称为独占锁

示例

下面是使用ReentrantReadWriteLock实现读写锁的示例:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void readData() {
        lock.readLock().lock(); // 获取读锁
        try {
            // 读取共享数据
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }

    public void writeData() {
        lock.writeLock().lock(); // 获取写锁
        try {
           // 修改或写入数据
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }
    }
}

在上面的示例代码中,readData方法通过调用lock.readLock()方法获取读锁,而writeData方法则通过调用lock.writeLock()方法获取写锁。
使用读写锁时,在读取共享数据时可以并发进行,即多个线程可以同时对同一段共享数据进行读取,而在修改或写入共享数据时,只有一个线程能进行操作,其他线程需要等待其完成。
需要注意的是,在使用ReentrantReadWriteLock实现读写锁时,写锁拥有最高的优先级,一旦写锁被请求,那么任何读锁或写锁的请求都会被阻塞,直到写锁完全释放(写锁现参与者本身也可以申请读锁的,这种情况下,由于写锁仍然持有,读锁的申请仍然被阻塞)

为什么不干脆把读操作设置为无锁?

那么这时候我们就会有一个疑问:既然ReentrantReadWriteLock的读锁是共享锁,那为什么不干脆把读操作设置为无锁?
想要弄清楚这个问题,首先要明白写锁的机制,写锁是一个独占锁,独占锁具有排它性,当一个线程持有写锁的时候,其他的线程所持有的读锁都会被阻塞(上面提到过)。
如果我们不为读操作加锁,那么当一个线程获取写锁在修改数据的时候,我们读到了这个修改之前的数据,然后线程修改完毕,我们会发现我们读取的内容和数据是对不上的,我们读出来和实际数据不一样的这种数据,称其为脏数据,这样就不具有同步性了(这个问题的本质和数据库脏读基本一致,后面我也会发布关于数据库的文章来详细介绍)。
但是,如果加上了读锁就不一样了,当有线程获取了写锁,在对数据进行修改的时候,其他线程获取读锁想要读取数据,就会被阻塞,等到写锁完全释放,持有读锁的线程才能读取。这样就保证了数据同步和避免读到脏数据的情况。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

君去何方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值