JUC
代码浅析
[3]
——基于
AQS
的锁
ReentrantReadWriteLock
ReentrantReadWriteLock
也是基于
AQS
实现的锁,它的特点是一个资源能够被多个读线程访问,或者被一个写线程访问,读和写是互斥的,可以同时有多个读但只能有一个写,大量读操作的场景下性能较好。
ReentrantReadWriteLock
并没有实现
Lock
接口,而是内部实现了
ReadLock
和
WriteLock
分别针对读和写操作。看起来像两个锁,但其实这两个锁只是进行了一层适配,它们的主体都是
Sync
,
ReadLock
和
WriteLock
分别使用
Sync
的共享和独占模式。
ReadLock
加锁和释放,就是向
sync
请求共享模式进入和释放
public
void
lock
() {
sync.acquireShared(1);
}
public
void
unlock
()
{
sync.releaseShared(1);
}
WriteLock
加锁和释放,就是向
sync
请求互斥模式进入和释放
public
void
lock() {
sync.acquire
(1);
}
public
void
unlock
()
{
sync.release(1);
}
sync
的实现有公平和非公平两种
(
下面介绍区别
)
,
sync
使用
int
的低
16
位表示写计数,高
16
位表示读计数,所以读锁和写锁的最高重入次数为
65535
,超出将抛出
Error
。
获取写锁的实现片段,逻辑是:
l
如果读计数不为
0
,失败;
l
如果写计数不为
0
并且不是当前线程持有锁,失败
l
如果写计数超出
65535
,失败,抛出
Error
l
如果写计数为
0
并且当前线程需要阻塞,或者
state
被其他线程改变了,失败
l
以上条件都不满足则当前线程拥有写锁
protected
final
boolean
tryAcquire
(
int
acquires) {
Thread current = Thread.currentThread();
int
c = getState();
int
w = exclusiveCount(c);
if
(c != 0) {
// (Note: if c != 0 and w == 0 then shared
count != 0)
if
(w == 0 || current !=
getExclusiveOwnerThread())
return
false
;
if
(w + exclusiveCount(acquires) >
MAX_COUNT)
throw
new
Error(
"Maximum
lock count exceeded"
);
}
if
((w == 0 &&
writerShouldBlock(current)) ||
!compareAndSetState(c, c +
acquires))
return
false
;
setExclusiveOwnerThread(current);
return
true
;
}
非公平
sync
的写线程在总是不需要阻塞
final
boolean
writerShouldBlock
(Thread current)
{
return
false
;
// writers can
always barge
}
公平
sync
的写线程只要
AQS
队列不为空并且不在第一个位置的就需要阻塞
final
boolean
writerShouldBlock(Thread current) {
// only proceed if queue is empty or
current thread at head
return
!isFirst(current);
}
写锁的释放,减去并检查
state
计数,为
0
则表示写锁已经可以释放了,不为
0
说明该线程重入了写锁并把剩余的计数写入
state
protected
final
boolean
tryRelease
(
int
releases) {
int
nextc = getState() - releases;
if
(Thread.currentThread() !=
getExclusiveOwnerThread())
throw
new
IllegalMonitorStateException();
if
(exclusiveCount(nextc) == 0) {
setExclusiveOwnerThread(
null
);
setState(nextc);
return
true
;
}
else
{
setState(nextc);
return
false
;
}
}
读锁的获取,
1
如果已经有线程获得写锁,并且不是当前线程获得的,失败
2
如果重入的读计数超出
65535
,失败,抛出
Error
3
否则如果线程不用阻塞,并且增加读计数成功,则成功获得读锁
4
如果第三步失败(可能由于线程需要阻塞或者
CAS
修改失败),
不断尝试去修改状态直到成功或者锁被写入线程占有(看
fullTryAcquireShared
的实现
)
protected
final
int
tryAcquireShared
(
int
unused) {
Thread current =
Thread.currentThread();
int
c = getState();
if
(exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() !=
current)
return
-1;
if
(sharedCount(c) == MAX_COUNT)
throw
new
Error(
"Maximum
lock count exceeded"
);
if
(!readerShouldBlock(current) &&
compareAndSetState(c, c +
SHARED_UNIT)) {
HoldCounter rh =
cachedHoldCounter;
if
(rh ==
null
|| rh.tid != current.getId())
cachedHoldCounter = rh =
readHolds.get();
rh.count++;
return
1;
}
return
fullTryAcquireShared(current);
}
final
int
fullTryAcquireShared(Thread current) {
HoldCounter rh = cachedHoldCounter;
if
(rh ==
null
|| rh.tid != current.getId())
rh = readHolds.get();
for
(;;) {
int
c = getState();
int
w = exclusiveCount(c);
if
((w != 0 &&
getExclusiveOwnerThread() != current) ||
((rh.count | w) == 0
&& readerShouldBlock(current)))
return
-1;
if
(sharedCount(c) == MAX_COUNT)
throw
new
Error(
"Maximum
lock count exceeded"
分享到:
相关推荐
它是实现Java并发包中锁和其他同步器的基础框架,例如ReentrantLock(可重入锁)、Semaphore(信号量)、CountDownLatch(倒计时门闩)、CyclicBarrier(循环栅栏)以及ReentrantReadWriteLock(可重入读写锁)等。...
在Java中,JUC(java.util.concurrent)包包含了多种并发控制和同步工具,如线程池、锁、并发容器等,这些工具使得开发者能够编写高效、安全、可维护的并发代码。以下将详细讲解其中的一些关键知识点: 1. **线程池...
- AQS维护了一个32位的state变量,ReentrantReadWriteLock利用这个变量的高16位表示读锁的重入次数,低16位表示写锁的重入次数。 3. **读锁和写锁的最大数量** - 由于state变量的范围是32位,理论上读锁和写锁的...
从JUC中的AQS引入,讲解Java volatile与AQS锁内存可见性
Java的并发编程是多线程和多任务处理的核心技术之一,而在Java并...开发者可以基于AQS创建复杂的同步结构,满足各种并发场景的需求。理解AQS的工作原理,对于使用Java并发包以及开发高性能的多线程应用具有重要的意义。
juc 的aqs介绍。
这个压缩包文件“个人学习JUC代码笔记总集”显然是一个个人的学习资源,记录了对JUC组件的理解和应用实例,特别适合已经有一定Java基础,想要深入学习并发编程的开发者。 JUC的主要目标是简化并发编程,提高多线程...
AQS通过内部维护一个基于链表的等待队列,有效地管理线程的同步和唤醒,从而实现锁和其他同步原语。 **AQS核心特性:** 1. **资源管理**:AQS定义了两种资源获取方式:独占和共享。独占模式下,只有一个线程能访问...
ReentrantReadWriteLock (读写锁) BlockingQueue(阻塞队列) 线程池 池化技术 线程池的优势 线程池的特点 线程池三大方法 线程池七大参数 线程池四种拒绝策略 ForkJoin 异步回调 Volatile 指令重排 JMM
AQS源码分析一、锁的介绍1.1 乐观锁/悲观锁1.2 共享锁/独占锁1.3 公平锁/非公平锁1.4 小结二、AQS框架结构介绍2.1 类图2.2 AQS数据结构三、源码详解3.1 acquire源码详解3.2 release源码详解四、从ReentranLock看公平...
本资源"JUC代码收集,java高并发多线程学习"显然是一个专注于探讨和学习JUC库的资料包。 JUC库包含多个子包,如`concurrent`, `atomic`, `locks`等,每个子包都有其特定的功能和用途: 1. **concurrent**:这是JUC...
JUC中的锁机制包括ReentrantLock(可重入锁)、ReadWriteLock(读写锁)等。ReentrantLock相比synchronized具有更细粒度的控制,支持公平性和非公平性,并提供了tryLock()方法来尝试获取锁,以及lockInterruptibly...
AQS作为Java并发工具包(JUC)中的一个核心抽象类,其设计目的是为了实现各种同步器(如锁、信号量等)。AQS主要通过三个核心组成部分来实现这些同步组件的功能: 1. **State变量及其CAS操作**:AQS维护了一个名为`...
《AQS和JUC知识点详解》 在Java并发编程领域,AbstractQueuedSynchronizer(AQS)和Java Util Concurrency(JUC)是两个至关重要的概念。它们为开发高效、线程安全的多线程程序提供了强大的工具。本文将深入解析这...
除了`synchronized`之外,Java还提供了更灵活的锁机制——`Lock`接口。`Lock`接口提供了比`synchronized`更强大的锁定机制,并且实现了更加精细的线程控制。 在示例中,使用了`ReentrantLock`类来实现自定义的锁: ...
Java并发编程是Java开发中的重要领域,而Java并发工具包(Java Concurrency Utility,简称JUC)则是Java标准库提供的一套强大而丰富的工具,它极大地简化了多线程环境下的编程工作。JUC主要包含在`java.util....
在这个"juc学习代码"的资源中,我们很显然会接触到Java并发编程的核心概念和实践。 首先,JUC库中的`java.util.concurrent`包包含了大量并发工具类,如`Semaphore`(信号量)、`CyclicBarrier`(循环屏障)、`...
### Java并发编程-AQS和JUC实战 #### 一、ReentrantLock 重入锁 **1.1 概述** - **基本介绍**: `ReentrantLock` 是一个实现了 `Lock` 接口的可重入互斥锁,提供比 `synchronized` 更丰富的功能。与 `synchronized...
juc并发编程脑图以及相关示例代码
AQS是Java并发包中的核心抽象类,它是基于FIFO队列的等待锁框架。许多并发工具,如ReentrantLock、Semaphore等,都基于AQS实现。AQS维护了一个内部状态以及一个等待线程的双端队列,通过共享或独占模式来控制资源的...