Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题
,可以支持多个相关的 Condition对象
。使用最多的Lock类是ReentrantLock、
ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock。
synchronized
方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。
虽然 synchronized
方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock
接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。
随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized
方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
ReentrantLock
将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock
的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread()
和 getHoldCount()
方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true
时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock
方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
ReadWriteLock 维护了一对相关的锁
,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁
可以由多个 reader 线程同时保持。写入锁
是独占的。
所有 ReadWriteLock 实现都必须保证 writeLock 操作的内存同步效果也要保持与相关 readLock 的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。
与互斥锁相比,读-写锁允许对共享数据进行更高级别的并发访问。虽然一次只有一个线程(writer 线程)可以修改共享数据,但在许多情况下,任何数量的线程可以同时读取共享数据(reader 线程),读-写锁利用了这一点。从理论上讲,与互斥锁相比,使用读-写锁所允许的并发性增强将带来更大的性能提高。在实践中,只有在多处理器上并且只在访问模式适用于共享数据时,才能完全实现并发性增强。
与互斥锁相比,使用读-写锁能否提升性能则取决于读写操作期间读取数据相对于修改数据的频率,以及数据的争用——即在同一时间试图对该数据执行读取或写入操作的线程数。例如,某个最初用数据填充并且之后不经常对其进行修改的 collection,因为经常对其进行搜索(比如搜索某种目录),所以这样的 collection 是使用读-写锁的理想候选者。但是,如果数据更新变得频繁,数据在大部分时间都被独占锁,这时,就算存在并发性增强,也是微不足道的。更进一步地说,如果读取操作所用时间太短,则读-写锁实现(它本身就比互斥锁复杂)的开销将成为主要的执行成本,在许多读-写锁实现仍然通过一小段代码将所有线程序列化时更是如此。最终,只有通过分析和测量,才能确定应用程序是否适合使用读-写锁。
尽管读-写锁的基本操作是直截了当的,但实现仍然必须作出许多决策,这些决策可能会影响给定应用程序中读-写锁的效果。这些策略的例子包括:
- 在 writer 释放写入锁时,reader 和 writer 都处于等待状态,在这时要确定是授予读取锁还是授予写入锁。Writer 优先比较普遍,因为预期写入所需的时间较短并且不那么频繁。Reader 优先不太普遍,因为如果 reader 正如预期的那样频繁和持久,那么它将导致对于写入操作来说较长的时延。公平或者“按次序”实现也是有可能的。
- 在 reader 处于活动状态而 writer 处于等待状态时,确定是否向请求读取锁的 reader 授予读取锁。Reader 优先会无限期地延迟 writer,而 writer 优先会减少可能的并发。
- 确定是否重新进入锁:可以使用带有写入锁的线程重新获取它吗?可以在保持写入锁的同时获取读取锁吗?可以重新进入写入锁本身吗?
- 可以将写入锁在不允许其他 writer 干涉的情况下降级为读取锁吗?可以优先于其他等待的 reader 或 writer 将读取锁升级为写入锁吗?
相关推荐
.NET LOCK使用方法 .NET框架中的Lock关键字用于控制多线程对共享资源的访问,确保在同一时间只有一个线程能够执行一个代码块。当一个线程访问被锁定的资源时,其它所有尝试获取锁的线程将被阻塞,直到锁被释放。 ...
这个实例将深入探讨`Lock`的使用,以及它在确保线程安全方面的作用。 在C#中,`Lock`是通过`System.Threading`命名空间下的`Monitor`类实现的。`Lock`关键字创建了一个同步块,当一个线程进入该同步块时,它会获取...
Android WakeLock 使用方法代码实例 Android WakeLock 是 Android 中的一个重要组件,它可以控制屏幕的背光开关,唤醒锁的意思是它可以在屏幕关闭时保持屏幕的点亮状态。下面是一个使用 WakeLock 的代码实例: ...
python-redis-lock 多个redis客户端访问同一个redis服务端,控制并发。 github:https://pypi.org/project/python-redis-lock/ 在使用这个库之前,需要安装如下: pip install python-redis-lock 使用锁的示例: ...
以下是一个简单的Lock使用示例,展示了ReentrantLock的使用: ```java ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { lock.lock(); // 获取...
"lock(this)的使用说明" lock(this)是C#语言中的一种同步机制,用于确保在多线程环境下对共享资源的访问安全。通过使用lock(this)语句,可以保证在同一时刻只有一个线程可以访问某个资源,防止多个线程同时访问同...
本篇文章将深入探讨`Lock`的使用以及它如何帮助解决并发问题。 1. **什么是Lock?** `Lock`是C#中的一种同步原语,通过`System.Threading`命名空间下的`Monitor`类实现。它提供了一种机制,使得同一时间只有一个...
三、进程互斥锁Lock使用 案例一:不使用互斥锁的多进程示例 下面的代码创建了10个进程,每个进程运行函数`foo`,没有使用互斥锁。由于缺少锁的保护,输出显示多个进程同时运行,可能导致并发问题: ```python ...
本文将深入探讨两种主要的锁机制:`synchronized`关键字和`Lock`接口,以及它们各自的特点、应用场景和使用方式。 一、Synchronized `synchronized`是Java中的一个内置关键字,用于提供线程安全。它的主要作用是...
在日常使用中,许多程序员、数据输入员以及对键盘快捷键有高需求的用户发现,Capslock键的位置在主键盘区中心,易于触及,如果能合理利用,可以大大提高工作速度。Capslock++就是为此目的设计的,它允许用户自定义...
### WINXP下无法使用CAPS LOCK键关闭Caps Lock指示灯 在Windows XP操作系统中,有用户反映遇到一个特殊的问题:即无法通过按下Caps Lock键来关闭键盘上的Caps Lock指示灯。这个问题虽然看似微不足道,但对于习惯了...
Lock锁是对象锁,仅在同一对象中,锁才会生效。(不做论证) (以下场景皆为单例模式下运行) lock.lock()的加锁方式,会使后续请求的线程堵塞等待。(方案A) lock.tryLock()的加锁方式,不会堵塞,会立即返回加锁...
在转换过程中,需要注意的是,由于两个锁文件的格式和包含的信息不完全相同,转换可能会丢失某些细节,因此建议在团队中统一使用一种包管理器以减少潜在问题。 ### 结论 `yarn.lock`和`package-lock.json`是...
Lock、Synchronized 和 ReentrantLock 的使用 Lock、Synchronized 和 ReentrantLock 是 Java 中三种常用的同步机制,每种机制都有其特点和使用场景。下面对这三种机制进行详细的分析和比较。 一、Synchronized ...
分布式锁DistributedLock是一个.NET库,它基于各种基础技术提供了健壮且易于使用的分布式互斥锁,读写器锁和信号灯。 使用DistributedLock,跨多个应用程序/机器同步对代码区域的访问非常简单: using ( await ...
本文将深入探讨C#中如何使用Lock和Redis分布式锁来解决并发问题,以秒杀系统为例进行阐述。 首先,让我们理解什么是并发控制。并发控制是指在多线程环境下确保数据的一致性和完整性,防止多个线程同时访问同一资源...
i3lock-改进了的屏幕储物柜 >是像slock这样的简单屏幕锁。 启动后,您会看到一个白色屏幕(您可以配置颜色/图像)。... 随着时间的流逝,i3...在OpenBSD上,i3lock使用bsd_auth(3)框架。 安装 请参阅。 要求 pkg-con
在这个例子中,`lock()`方法尝试使用`SETNX`获取锁,而`unlock()`方法在释放锁之前会检查是否确实拥有锁,防止误删其他实例的锁。注意,实际应用中还需要处理锁自动续期、超时未释放等问题,以防止死锁。 在测试...