Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
醒狮指南
JavaGuide
提交
d6ad33c3
J
JavaGuide
项目概览
醒狮指南
/
JavaGuide
与 Fork 源项目一致
从无法访问的项目Fork
通知
5
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
JavaGuide
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
d6ad33c3
编写于
11月 27, 2019
作者:
S
Snailclimb
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Update AQS.md
上级
a5c53a42
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
120 addition
and
6 deletion
+120
-6
docs/java/Multithread/AQS.md
docs/java/Multithread/AQS.md
+120
-6
未找到文件。
docs/java/Multithread/AQS.md
浏览文件 @
d6ad33c3
...
...
@@ -54,10 +54,9 @@ AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列
private
volatile
int
state
;
//共享变量,使用volatile修饰保证线程可见性
```
状态信息通过protected类型的
getState,setState,compareAndSetState
进行操作
状态信息通过protected类型的
`getState`
,
`setState`
,
`compareAndSetState`
进行操作
```
java
//返回同步状态的当前值
protected
final
int
getState
()
{
return
state
;
...
...
@@ -76,10 +75,125 @@ protected final boolean compareAndSetState(int expect, int update) {
**AQS定义两种资源共享方式**
-
**Exclusive**
(独占):只有一个线程能执行,如ReentrantLock。又可分为公平锁和非公平锁:
-
公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
-
非公平锁:当线程要获取锁时,先通过 CAS 操作和队列头的线程去抢锁,如果没抢到,当前线程再加入到队列中等待唤醒。
-
**Share**
(共享):多个线程可同时执行,如Semaphore/CountDownLatch。Semaphore、CountDownLatCh、 CyclicBarrier、ReadWriteLock 我们都会在后面讲到。
**1)Exclusive**
(独占)
只有一个线程能执行,如ReentrantLock。又可分为公平锁和非公平锁,ReentrantLock 同时支持两种锁,下面以 ReentrantLock 对这两种锁的定义做介绍:
-
公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
-
非公平锁:当线程要获取锁时,先通过两次 CAS 操作去抢锁,如果没抢到,当前线程再加入到队列中等待唤醒。
> 说明:下面这部分关于 `ReentrantLock` 源代码内容节选自:https://www.javadoop.com/post/AbstractQueuedSynchronizer-2,这是一篇很不错文章,推荐阅读。
**下面来看 ReentrantLock 中相关的源代码:**
ReentrantLock 默认采用非公平锁,因为考虑获得更好的性能,通过 boolean 来决定是否用公平锁(传入 true 用公平锁)。
```
java
/** Synchronizer providing all implementation mechanics */
private
final
Sync
sync
;
public
ReentrantLock
()
{
// 默认非公平锁
sync
=
new
NonfairSync
();
}
public
ReentrantLock
(
boolean
fair
)
{
sync
=
fair
?
new
FairSync
()
:
new
NonfairSync
();
}
```
ReentrantLock 中公平锁的
`lock`
方法
```
java
static
final
class
FairSync
extends
Sync
{
final
void
lock
()
{
acquire
(
1
);
}
// AbstractQueuedSynchronizer.acquire(int arg)
public
final
void
acquire
(
int
arg
)
{
if
(!
tryAcquire
(
arg
)
&&
acquireQueued
(
addWaiter
(
Node
.
EXCLUSIVE
),
arg
))
selfInterrupt
();
}
protected
final
boolean
tryAcquire
(
int
acquires
)
{
final
Thread
current
=
Thread
.
currentThread
();
int
c
=
getState
();
if
(
c
==
0
)
{
// 1. 和非公平锁相比,这里多了一个判断:是否有线程在等待
if
(!
hasQueuedPredecessors
()
&&
compareAndSetState
(
0
,
acquires
))
{
setExclusiveOwnerThread
(
current
);
return
true
;
}
}
else
if
(
current
==
getExclusiveOwnerThread
())
{
int
nextc
=
c
+
acquires
;
if
(
nextc
<
0
)
throw
new
Error
(
"Maximum lock count exceeded"
);
setState
(
nextc
);
return
true
;
}
return
false
;
}
}
```
非公平锁的 lock 方法:
```
java
static
final
class
NonfairSync
extends
Sync
{
final
void
lock
()
{
// 2. 和公平锁相比,这里会直接先进行一次CAS,成功就返回了
if
(
compareAndSetState
(
0
,
1
))
setExclusiveOwnerThread
(
Thread
.
currentThread
());
else
acquire
(
1
);
}
// AbstractQueuedSynchronizer.acquire(int arg)
public
final
void
acquire
(
int
arg
)
{
if
(!
tryAcquire
(
arg
)
&&
acquireQueued
(
addWaiter
(
Node
.
EXCLUSIVE
),
arg
))
selfInterrupt
();
}
protected
final
boolean
tryAcquire
(
int
acquires
)
{
return
nonfairTryAcquire
(
acquires
);
}
}
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final
boolean
nonfairTryAcquire
(
int
acquires
)
{
final
Thread
current
=
Thread
.
currentThread
();
int
c
=
getState
();
if
(
c
==
0
)
{
// 这里没有对阻塞队列进行判断
if
(
compareAndSetState
(
0
,
acquires
))
{
setExclusiveOwnerThread
(
current
);
return
true
;
}
}
else
if
(
current
==
getExclusiveOwnerThread
())
{
int
nextc
=
c
+
acquires
;
if
(
nextc
<
0
)
// overflow
throw
new
Error
(
"Maximum lock count exceeded"
);
setState
(
nextc
);
return
true
;
}
return
false
;
}
```
总结:公平锁和非公平锁只有两处不同:
1.
非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候恰巧锁没有被占用,那么直接就获取到锁返回了。
2.
非公平锁在 CAS 失败后,和公平锁一样都会进入到 tryAcquire 方法,在 tryAcquire 方法中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接 CAS 抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,乖乖排到后面。
公平锁和非公平锁就这两点区别,如果这两次 CAS 都不成功,那么后面非公平锁和公平锁是一样的,都要进入到阻塞队列等待唤醒。
相对来说,非公平锁会有更好的性能,因为它的吞吐量比较大。当然,非公平锁让获取锁的时间变得更加不确定,可能会导致在阻塞队列中的线程长期处于饥饿状态。
**2)Share**
(共享)
多个线程可同时执行,如Semaphore/CountDownLatch。Semaphore、CountDownLatCh、 CyclicBarrier、ReadWriteLock 我们都会在后面讲到。
ReentrantReadWriteLock 可以看成是组合式,因为ReentrantReadWriteLock也就是读写锁允许多个线程同时对某一资源进行读。
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录