独占锁与共享锁有什么区别?

139
根据维基百科的说法:
共享锁有时称为“读锁”,而独占锁有时称为“写锁”。您能解释一下“共享”和“独占”这些术语背后的原因吗?

1
非独占锁是共享锁的另一个名称吗? - Ramesh Papaganti
5个回答

522

我写下了这个答案,因为我认为这是一个有趣(而且合适)的比喻:

将一件可以锁住的物品看作是教室里的一个黑板(可锁定),上面有一个老师(写者)和许多学生(读者)。

当老师在黑板上写东西时(独占锁):

  1. 因为她正在写作并挡住了你的视线,所以没有人能够阅读 => 如果对象被独占锁定,则无法获得共享锁

  2. 其他老师也不会走过来开始写作,否则黑板就变得不可读并困惑了学生 => 如果对象被独占锁定,则无法获得其他独占锁

当学生们(共享锁)阅读黑板上的内容时:

  1. 他们都可以一起阅读上面的内容 => 多个共享锁可以共存

  2. 老师会等待他们阅读完毕才清除黑板以便继续写作 => 如果一个或多个共享锁已存在,则无法获得独占锁


2
非常好的解释。然而,PO 询问“共享”和“独占”名称来源的起源,而不是对术语本身的解释。 - serhio
1
@KanagaveluSugumar,是的,这是真的。如果另一个实体已经持有同一对象的读锁,那么您就无法获取写锁。这就是读写锁的全部意义。如果您在其他人正在读取它时进行覆盖,那么他们会读到什么呢?我不知道为什么你选择特别挑选了“可重入”读写锁,但是可重入意味着可重入锁的所有者可以再次'lock()'它,并且第一个' lock() '调用之后的所有后续调用都将立即成功返回。也就是说,您可以成功地锁定已拥有的某些东西。 - ArjunShankar
2
您还提到:“我认为可以随时获得写锁,否则由于持续读取可能会导致写入饥饿”-这根本不可能。在某些其他实体已经持有读/写锁时,无法获得写锁。可能发生的是,如果多个实体已经等待锁定对象,则当锁选择谁在下一个(由当前所有者解锁)获得锁时,等待的“writer”将优先于等待的读者。这是关于策略的问题。 - ArjunShankar
谢谢!我选择了ReentrantReadWriteLock;因为这是java中ReadWriteLock的实现类。那么,当写线程开始等待时,是否会引发任何标志或设置更高的优先级以指示进一步的新读线程等待?因为如何避免由于连续的读请求而导致写线程挨饿? - Kanagavelu Sugumar
@ArjunShankar的回答非常完美。但是如果有一个进程正在执行“select * from table blackboard”(尚未完成),然后发生了插入操作,会发生什么?插入操作会等待选择操作吗?选择*是否对“新记录”应用共享锁? - Đinh Anh Huy
显示剩余7条评论

44

这很简单。读锁也被称为共享锁,因为多个进程可以同时读取。读锁的目的是防止另一个进程获取写锁。相比之下,写锁在写操作完成期间会禁止所有其他操作,这就是为什么它被描述为独占。

因此,读锁表示“您现在可以读取,但如果您想要写入,则必须等待”,而写锁表示“您必须等待”。


我知道您正在为学习提供支持,但我忍不住想讲一番。

不当使用锁是性能问题的主要原因。使用区分读写锁的锁定系统是一个好的起点,但仔细设计有时可以消除大部分锁定需求。例如,会话状态永远不应该保存在每个状态元素的一个全局集合中。

我实际上看到过这样的做法。这是一个可怕的设计,导致装箱和每次会话状态更改都需要更改集合,涉及长时间的写锁。开销非常大,实际上将服务器降为单线程行为。

将所有会话状态聚合到一个结构中只是一个巨大的改进。会话状态的更改仅更改会话状态结构的成员的值。由于没有其他会话有机会直接引用会话状态,因此更新的唯一集合是会话列表。因此,在会话期间完全不需要锁定,只需要在开始和结束时进行锁定,吞吐量提高了3000倍。

另一个常见的锁定场景是用户应用程序的线程之间共享的资源。大多数现代框架使用消息而不是锁来解决这个问题。当您“转换到UI线程”时,实际上是将包含函数指针和一些参数(或委托和堆栈帧,具体取决于实现)的消息排队。


大多数现代框架使用消息而不是锁来解决这个问题。这种消息技术有官方名称吗?我搜索了一下,但没有找到相关的问题。 - Chubby Cows

9
  • 排他或写锁定使进程独占地访问指定文件的写入部分。当写锁定生效时,没有其他进程可以锁定该文件的那一部分。

  • 共享或读锁定禁止任何其他进程请求指定文件部分的写锁定。但是,其他进程可以请求读锁定。

更多信息请参见:http://www.gnu.org/software/libc/manual/html_node/File-Locks.html


2

在数据库方面,原则也是相同的。根据Oracle文档,独占锁模式可防止关联资源被共享。获得该锁模式以修改数据。第一个锁定资源的事务是唯一能够在释放独占锁之前更改资源的事务。

共享锁模式允许关联资源在根据所涉及的操作而共享。多个用户读取数据时可以共享数据,保持共享锁以防止写入者(需要独占锁)进行并发访问。多个事务可以在同一资源上获取共享锁。


1
  • 独占锁 不允许读取和写入操作。

  • 共享锁 只允许读取操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接