渣某人读源码之ReentrantLock之FairSync之加锁
瞎扯
好家伙,CSDN这写一个文章好像很复杂的样子啊!!!!
被AQS的源码折磨的死去活来的
好家伙,最近看AQS的源码的时候,从什么acquire开始就啥也没看懂,拖了两天,实在受不了了,我就去B站找了个视频,嘿嘿,真棒,老师讲的真好。
看一下Idea的神仙断点技能,渣某人比较菜,最近才发现
我在这里加了断点,方便对源码的debug,然后断点有条件的来着
上Demo
package thread;
import java.sql.Time;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author :zhangst.
* @Date :Created in 22:55 2021/1/26
* @Version: 1.0
*/
class Phone {
Lock lock = new ReentrantLock(true);
public void sleepLongTime() {
lock.lock();
try {
TimeUnit.MINUTES.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ReenterLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
//最开始只有一个A线程(是指后面的都注释了),Debug条件是"A".equals(Thread.currentThread().getName())
new Thread(() -> {
try {
phone.sleepLongTime();
} catch (Exception e) {
e.printStackTrace();
}
}, "A" ).start();
//然后加上了B线程,Debug条件是"B".equals(Thread.currentThread().getName())
new Thread(() -> {
try {
phone.sleepLongTime();
} catch (Exception e) {
e.printStackTrace();
}
}, "B" ).start();
//最后加上了C线程,Debug条件是"C".equals(Thread.currentThread().getName())
new Thread(() -> {
try {
phone.sleepLongTime();
} catch (Exception e) {
e.printStackTrace();
}
}, "C" ).start();
}
}
然后是我对一点源码的注解,写的不好,勿喷啊,哈哈
ReentrantLock
public void lock() {
sync.lock();
}
final void lock() {
acquire(1);//T1就一直返回
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&//T1返回True,false直接返回,T2返回false
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//T2 初始化节点之后,直接返回T2的Node,
selfInterrupt();
}
//尝试获取锁
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();//当前线程
int c = getState();//T1 取到0,T2 state为1
if (c == 0) {
if (!hasQueuedPredecessors() &&//T1 !hasQueuedPredecessors 为true,继续执行,设置 acquires 为 1
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;
}
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());//T1 进来,头等于尾,h != t直接返回false
}
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;//T3走到这里,入队列
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);//T2直接走到这里
return node;
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);//确切的说是停在这里,别问,问就是debug出来的
setBlocker(t, null);
}
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))//T2第一次循环,初始化节点
tail = head;
} else {//T2再一次进来的时候,tail已经不是空了
node.prev = t;//设置这个,后面有用
if (compareAndSetTail(t, node)) {//入队列
t.next = node;
return t;
}
}
}
}
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
final boolean acquireQueued(final Node node, int arg) {//T2进入arg = 1
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {//死循环,编译成字节码时,短而且快
final Node p = node.predecessor();//返回node 的前节点,T3的前节点就是T2嘛
if (p == head && tryAcquire(arg)) {//T2p == head 为 true,执行tryAcquire,返回false;T3的前节点不是头,过
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&//T2先返回false,然后重新死循环,第二次返回true,继续;T3走到这里,然后返回false,继续死循环;再一次进去,返回true;然后和T2一样卡死
parkAndCheckInterrupt())//
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)//之前有设置过,为tail
throw new NullPointerException();
else
return p;//T2进入这里
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {//注意这里的pred是前节点
int ws = pred.waitStatus;//T2进来 waitStatus 为 0
if (ws == Node.SIGNAL)//SIGNAL = -1,T2第二次进来,执行这里面的代码;注意T3进来的时候这里的是前节点的ws哦,是0哦,
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. 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, ws, Node.SIGNAL);//设置前节点 -1 为什么是设置前节点呢?只要是 -1表示睡眠转态,是否睡眠需要别;T3也是到这里;把前面的节点改成-1;然后回去死循环;为什么要自旋两次?1. 尽最大努力加锁;两次的话对于计算机性能最好
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);//进入之后停在这里等待唤醒
return Thread.interrupted();
}