当前位置: 首页 > news >正文

【多线程】读写锁(Read-Write Lock)是什么?

【多线程】读写锁(Read-Write Lock)是什么?

本文来自于我关于多线程系列文章。欢迎阅读、点评与交流
1.【多线程】互斥锁(Mutex)是什么?
2.【多线程】临界区(Critical Section)是什么?
3.【多线程】计算机领域中的各种锁
4.【多线程】信号量(Semaphore)是什么?
5.【多线程】信号量(Semaphore)常见的应用场景
6.【多线程】条件变量(Condition Variable)是什么?
7.【多线程】监视器(Monitor)是什么?
8.【多线程】什么是原子操作(Atomic Operation)?
9.【多线程】竞态条件(race condition)是什么?
10.【多线程】无锁数据结构(Lock-Free Data Structures)是什么?
11.【多线程】线程休眠(Thread Sleep)的底层实现
12.【多线程】多线程的底层实现
13.【多线程】读写锁(Read-Write Lock)是什么?

核心概念

读写锁,也称为“共享-独占锁”,是一种同步机制,用于解决“读-写”并发场景下的性能问题。

它的核心思想是:将数据的“读”操作和“写”操作区别对待

  • 读操作(共享):不会修改数据,多个线程同时读取同一份数据不会产生问题。
  • 写操作(独占):会修改数据,必须互斥地进行,并且在写的过程中,不允许任何其他线程(无论是读还是写)访问数据。

读写锁的三种状态

  1. 读模式加锁(共享锁)

    • 当没有线程持有写锁时,任意数量的线程可以同时持有读锁。
    • 这种状态下,所有读线程可以并发访问数据,大大提高了读操作的吞吐量。
  2. 写模式加锁(独占锁)

    • 当有一个线程持有写锁时,其他任何线程(无论是读还是写)都无法获取锁,必须等待写锁被释放。
    • 这种状态下,写操作是串行化的,保证了数据的一致性。
  3. 未加锁

    • 没有任何线程持有锁。

工作原理与规则

读写锁遵循一套明确的规则来管理锁的获取:

  • 读-读不互斥:多个读线程可以同时访问。这是提升性能的关键。
  • 读-写互斥:如果一个线程正在读,另一个线程请求写,则写线程必须等待所有读线程释放锁。反之,如果一个线程正在写,则读线程必须等待写线程释放锁。
  • 写-写互斥:同一时间只允许一个写线程进行。

为什么需要读写锁?

在没有读写锁的情况下,我们通常会使用普通的互斥锁。互斥锁的特点是,无论线程是读还是写,每次只允许一个线程访问共享资源。

问题:在读多写少的场景下(比如网站首页的访问量远大于后台管理员的修改次数),使用互斥锁会导致大量读操作之间也相互阻塞,严重限制了系统的并发性能。

读写锁的优势:在读多写少的场景中,读写锁允许多个读者同时进行,从而极大地提高了程序的并发度和吞吐量。

一个生动的比喻

把共享数据想象成一个公共黑板

  • 互斥锁:就像一把唯一的钥匙。无论你是想黑板(读)还是擦写黑板(写),你必须拿到这把钥匙才能走到黑板前。一个人用完后,下一个人才能用。
  • 读写锁:规则更智能。
    • 读操作:所有人都可以同时去看黑板,不需要排队。
    • 写操作:如果有人要擦写黑板,他必须等所有正在看的人都离开后,才能独自上前书写,并且在书写时,不允许其他人围观。
    • 如果有人在看的时候,有人想写,那么他会阻止新来的人继续看(防止“写线程饥饿”),等当前所有看的人都离开后,他才能开始写。

潜在问题:写线程饥饿

在某些实现中,如果读线程源源不断地到来(即始终有至少一个读锁被持有),可能会导致写线程长时间甚至永远无法获取锁,这种现象称为“写线程饥饿”。

现代的读写锁实现(如 Java 的 ReentrantReadWriteLock)通常提供了公平模式来解决这个问题。在公平模式下,锁会按照线程请求的顺序(近似地)来分配,避免了写线程的无限期等待。

代码示例(Java)

Java 中的 ReentrantReadWriteLock 是读写锁的一个经典实现。

import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockDemo {private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();private static int sharedData = 0;public static void main(String[] args) {// 启动多个读线程for (int i = 0; i < 5; i++) {new Thread(ReadWriteLockDemo::readData, "Reader-" + i).start();}// 启动一个写线程new Thread(ReadWriteLockDemo::writeData, "Writer-1").start();// 启动另一个写线程new Thread(ReadWriteLockDemo::writeData, "Writer-2").start();}public static void readData() {lock.readLock().lock(); // 获取读锁try {System.out.println(Thread.currentThread().getName() + " is reading data: " + sharedData);Thread.sleep(1000); // 模拟读操作耗时} catch (InterruptedException e) {e.printStackTrace();} finally {lock.readLock().unlock(); // 释放读锁System.out.println(Thread.currentThread().getName() + " finished reading.");}}public static void writeData() {lock.writeLock().lock(); // 获取写锁try {System.out.println(Thread.currentThread().getName() + " is writing data.");sharedData++;Thread.sleep(2000); // 模拟写操作耗时System.out.println(Thread.currentThread().getName() + " finished writing. New data: " + sharedData);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.writeLock().unlock(); // 释放写锁}}
}

可能的输出结果
你会观察到,多个“Reader”线程几乎同时开始和结束(读读并发),而两个“Writer”线程则是严格地一个接一个执行(写写互斥),并且在写线程执行时,没有读线程能介入(读写互斥)。

总结

特性互斥锁读写锁
并发性高(在读多写少场景下)
粒度细(区分读和写)
适用场景读写操作频率相当,或代码逻辑简单读多写少,对读性能要求高的场景

总而言之,读写锁是一种非常有效的工具,它通过分离读和写操作,在保证数据一致性的前提下,显著提升了并发程序的性能。

http://www.dtcms.com/a/445811.html

相关文章:

  • 电子商务网站建设步骤百度文库网站ip地址 a记录
  • 常规可见光相机在工业视觉检测中的应用
  • 佛山企业网站建设平台如何把官网
  • Vue3双向数据绑定v-model
  • Vue keep-alive
  • Vue中的hash模式和history模式
  • 微信网站 影楼电商网站开发代码
  • 如何更改PPT的比例大小
  • 【MediaMTX】centos 7 安装MediaMTX
  • 网站开发中 即将上线哈尔滨市建设厅网站
  • linux部署docker(国内镜像)
  • 深入理解HarmonyOS ArkTS语法:从组件化到状态管理
  • 东莞网站制作十强python培训费用大概多少
  • 网站嵌入视频代码郑州短视频运营公司
  • 【Linux】安装配置mysql中出现的问题1
  • CMU15445(2023fall) Project #1 - Buffer Pool Manager优化分析
  • Vue 基础(实战模板与命名指南)
  • 葫芦岛建设信息网站营销专业就业前景
  • 保定网站推广哪家好专业团队张伟图片
  • leetcode 1219 黄金矿工
  • 【Camera】MTK平台的一些基础认识(待补充)
  • Go基础:用Go语言操作MySQL详解
  • 数字短链接生成郑州seo优化
  • 网站排版尺寸安装好的字体怎么用wordpress
  • 如何利用企业微信SCRM打造精准客户营销策略?
  • AI 编程 Trae 如何去 AI 味(以用户管理系统为例子)
  • 【National Treasure2】
  • 【LLM4EDA】: Part 9--LLM4EDA的优化与建模
  • 用parser_tools插件来解析SQL语句
  • 湖北住房和城乡建设厅网站phpmysql做网站