本文为读取jdk源码的笔记所作。关注非公平锁。读取AQS源码建议先了解下CAS机制,以及双向链表的相关知识。
入口:ReentrantLock.lock()方法
public
void
lock
(
)
{
sync
.
lock
(
)
;
}
调用sync的抽象方法lock
static
abstract
class
Sync
extends
AbstractQueuedSynchronizer
{
private
static
final
long
serialVersionUID
=
-5179523762034025860
L
;
/**
* Performs {
@link
Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract
void
lock
(
)
;
}
默认具体由Sync的子类NonfairSync实现lock方法
final
static
class
NonfairSync
extends
Sync
{
private
static
final
long
serialVersionUID
= 7316153563782823691
L
;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final
void
lock
(
)
{
if
(
compareAndSetState
(
0
,
1
))
setExclusiveOwnerThread
(
Thread
.
currentThread
(
))
;
else
acquire
(
1
)
;
}
}
final
static
class
NonfairSync
extends
Sync
{
final
void
lock
(
)
{
if
(
compareAndSetState
(
0
,
1
))
setExclusiveOwnerThread
(
Thread
.
currentThread
(
))
;
else
acquire
(
1
)
;
}
}
static
abstract
class
Sync
extends
AbstractQueuedSynchronizer
{
}
public
abstract
class
AbstractQueuedSynchronizer
extends
AbstractOwnableSynchronizer
implements
java
.
io
.
Serializable
{
public
final
void
acquire
(
int
arg
)
{
if
(
!
tryAcquire
(
arg
)
&&
acquireQueued
(
addWaiter
(
Node
.
EXCLUSIVE
)
,
arg
))
selfInterrupt
(
)
;
}
}
首先看tryAcquire(arg) 的实现,该类由子类NonfairSync重写,再次尝试通过CAS方式获得锁。
protected
final
boolean
tryAcquire
(
int
acquires
)
{
return
nonfairTryAcquire
(
acquires
)
;
}
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
;
}
如果再次通过CAS获得锁失败,将会调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg))方法,这是AQS机制的核心。
先看addWaiter(Node.EXCLUSIVE), arg)方法
private
Node
addWaiter(
Node
mode) {
Node
node
=
new
Node(
Thread.
currentThread(),
mode);
// Try the fast path of enq; backup to full enq on failure
Node
pred
=
tail;
if (
pred
!=
null) {
node.
prev
=
pred;
if (
compareAndSetTail(
pred,
node)) {
pred.
next
=
node;
return
node;
}
}
enq(
node);
return
node;
}
Node的存储结构:
static
final
class
Node
{
/** waitStatus value to indicate thread has cancelled */
static
final
int
CANCELLED
=
1
;
/** waitStatus value to indicate successor's thread needs unparking */
static
final
int
SIGNAL
=
-1
;
/** waitStatus value to indicate thread is waiting on condition */
static
final
int
CONDITION
=
-2
;
/** Marker to indicate a node is waiting in shared mode */
static
final
Node
SHARED
=
new
Node
(
)
;
/** Marker to indicate a node is waiting in exclusive mode */
static
final
Node
EXCLUSIVE
=
null
;
volatile
Node
prev
;
volatile
Node
next
;
volatile
Thread
thread
;
Node
nextWaiter
;
}
private Node enq
(
final
Node
node
) {
for
(;;
) {
Node t = tail;
if
(
t ==
null
) { // Must initialize
Node h = new Node
(); // Dummy header
h
.next = node;
node
.prev = h;
if
(
compareAndSetHead(
h
)) {
tail = node;
return h;
}
}
else {
node
.prev = t;
if
(
compareAndSetTail(
t,
node
)) {
t
.next = node;
return t;
}
}
}
}
该段代码的主要将没有获得锁的线程通过双向链表的形式进行存储。
将新建的当前线程的排它锁类型的节点传入方法acquireQueued中
final
boolean
acquireQueued
(
final
Node
node
,
int
arg
)
{
try
{
boolean
interrupted
=
false
;
for
(
;;
)
{
final
Node
p
=
node
.
predecessor
(
)
;
if
(
p
==
head
&&
tryAcquire
(
arg
))
{
setHead
(
node
)
;
p
.
next
=
null
;
// help GC
return
interrupted
;
}
if
(
shouldParkAfterFailedAcquire
(
p
,
node
)
&&
parkAndCheckInterrupt
(
))
interrupted
=
true
;
}
}
catch
(
RuntimeException
ex
)
{
cancelAcquire
(
node
)
;
throw
ex
;
}
}
parkAndCheckInterrupt进行睡眠。
shouldParkAfterFailedAcquire方法是过滤那些CANCELLED的节点,关键要看懂do while 那段代码。可以自己画图理解。
private
static
boolean
shouldParkAfterFailedAcquire
(
Node
pred
,
Node
node
)
{
int
s
=
pred
.
waitStatus
;
if
(
s
<
0
)
/*
* This node has already set status asking a release
* to signal it, so it can safely park
*/
return
true
;
if
(
s
>
0
)
{
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do
{
node
.
prev
=
pred
=
pred
.
prev
;
}
while
(
pred
.
waitStatus
>
0
)
;
pred
.
next
=
node
;
}
else
/*
* Indicate that we need a signal, but don't park yet. Caller
* will need to retry to make sure it cannot acquire before
* parking.
*/
compareAndSetWaitStatus
(
pred
,
0
,
Node
.
SIGNAL
)
;
return
false
;
}
最后Thread.currentThread().interrupt();到这里锁就结束了。
AQS可以理解成一个存储争用锁的等待线程的存储以及状态变更的队列。
ReentrantLock.lock()通过CAS机制竞争到锁的线程继续执行,其余线程睡觉的机制实现同步机制。
释放锁关键为unparkSuccessor这段代码
private
void
unparkSuccessor
(
Node
node
)
{
/*
* Try to clear status in anticipation of signalling. It is
* OK if this fails or if status is changed by waiting thread.
*/
compareAndSetWaitStatus
(
node
,
Node
.
SIGNAL
,
0
)
;
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node
s
=
node
.
next
;
if
(
s
==
null
||
s
.
waitStatus
>
0
)
{
s
=
null
;
for
(
Node
t
=
tail
;
t
!=
null
&&
t
!=
node
;
t
=
t
.
prev
)
if
(
t
.
waitStatus
<=
0
)
s
=
t
;
}
if
(
s
!=
null
)
LockSupport
.
unpark
(
s
.
thread
)
;
}
以上纯属个人解读