01ReentrantLock

一、锁的实现(设计思维)

  1.锁的互斥特性—>共享资源—>标记(0无锁,1代表有锁)

  2.没有抢占到锁的线程?—>释放CPU资源【等待、唤醒】

  3.等待的线程怎么存储?—>数据结构去存储一系列等待中的线程,FIFO(等待队列)

  4.公平和非公平(能否插队)

  5.重入的特性(识别是否同一个人?ThreadId)

二、技术方案

  1.volatile state=0(无锁),1代表持有锁,>1代表重入锁

  2.wait/notify | condition需要唤醒指定线程。[LockSupport.park(); —>unpark(thread)] unsafe类中提供的一个方法

  3.双向链表

  4.逻辑层面去实现

  5.在某一个地方存储当前获得锁的线程的ID,判断下次抢占锁的线程是否同一个

三、源码

  1.lock.lock()方法做了啥

  01ReentrantLock

 

 

  2.lock.lock()调用了Sync(ReentrantLock类中的静态抽象类)的lock方法,sync是在ReentrantLock的构造方法中赋值的,无参构造函数中默认是非公平锁,有参的根据传入参数决定公平还是非公平。

  3.调用非公平锁NonfairSync的lock()方法:

  

1 final void lock() {
2     //通过CAS乐观锁机制抢占互斥资源
3     if (compareAndSetState(0, 1))//将state改为1
4         //抢占成功,存储当前线程
5         setExclusiveOwnerThread(Thread.currentThread());
6     else
7         //抢占失败的线程逻辑 
8         acquire(1);
9 }  

  4.抢占失败的具体逻辑

1 public final void acquire(int arg) {
2       if (!tryAcquire(arg) &&            
3          acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
4             selfInterrupt();
5 }    
 1 //4.1tryAcquire()方法中的逻辑
 2 final boolean nonfairTryAcquire(int acquires) {
 3             //获得当前线程
 4             final Thread current = Thread.currentThread();
 5             int c = getState();
 6             if (c == 0) {//无锁
 7                 if (compareAndSetState(0, acquires)) {//cas抢占锁
 8                     setExclusiveOwnerThread(current);
 9                     return true;
10                 }
11             }
12             //判断重入?
13             else if (current == getExclusiveOwnerThread()) {
14                 int nextc = c + acquires;//增加state的值
15                 if (nextc < 0) // overflow
16                     throw new Error("Maximum lock count exceeded");
17                 setState(nextc);//并不需要cas,因为已经是持有锁的状态
18                 return true;
19             }
20             return false;
21         }    
 1 //4.2addWaiter()将未获得锁的线程加入到队列
 2 private Node addWaiter(Node mode) {
 3         Node node = new Node(Thread.currentThread(), mode);
 4         // Try the fast path of enq; backup to full enq on failure
 5         Node pred = tail;
 6         if (pred != null) {
 7             node.prev = pred;
 8             if (compareAndSetTail(pred, node)) {
 9                 pred.next = node;
10                 return node;
11             }
12         }
13         enq(node);
14         return node;
15     }
16 
17 
18 private Node enq(final Node node) {
19         for (;;) {
20             Node t = tail;
21             if (t == null) { // Must initialize
22                 if (compareAndSetHead(new Node()))
23                     tail = head;
24             } else {
25                 node.prev = t;
26                 if (compareAndSetTail(t, node)) {
27                     t.next = node;
28                     return t;
29                 }
30             }
31         }
32     }

01ReentrantLock

  

 1 //4.3acquireQueued()去抢占锁或者阻塞
 2 final boolean acquireQueued(final Node node, int arg) {
 3         boolean failed = true;
 4         try {
 5             boolean interrupted = false;
 6             for (;;) {
 7                 final Node p = node.predecessor();
 8                 if (p == head && tryAcquire(arg)) {//前驱节点是否head&&抢占一次锁是否成功
 9                     setHead(node);
10                     p.next = null; // help GC
11                     failed = false;
12                     return interrupted;
13                 }
14                 if (shouldParkAfterFailedAcquire(p, node) &&
15                     parkAndCheckInterrupt())
16                     interrupted = true;
17             }
18         } finally {
19             if (failed)
20                 cancelAcquire(node);
21         }
22     }
23 
24 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
25         int ws = pred.waitStatus;
26         if (ws == Node.SIGNAL)
27             return true;
28         if (ws > 0) {//取消状态的节点是大于0
29             //将取消状态的节点从链表中移除
30             do {
31                 node.prev = pred = pred.prev;
32             } while (pred.waitStatus > 0);
33             pred.next = node;
34         } else {
35             //将前驱节点的waitStatus设置为-1
36             compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
37         }
38         return false;
39     }
40 
41 //阻塞当前线程
42 private final boolean parkAndCheckInterrupt() {
43         LockSupport.park(this);
44         return Thread.interrupted();
45     }
46 
47 
48 final Node predecessor() throws NullPointerException {
49             Node p = prev;
50             if (p == null)
51                 throw new NullPointerException();
52             else
53                 return p;
54         }

01ReentrantLock

 

   5.lock.unlock()做了啥?

   调用aqs的release()方法

1 public final boolean release(int arg) {
2         if (tryRelease(arg)) {
3             Node h = head;
4             if (h != null && h.waitStatus != 0)
5                 unparkSuccessor(h);
6             return true;
7         }
8         return false;
9     }
//5.1设置waitstate值,并将exclusiveOwnerThread置为null
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

01ReentrantLock

 

 1 //5.2唤醒一个队列中一个阻塞的线程
 2 private void unparkSuccessor(Node node) {
 3         int ws = node.waitStatus;
 4         if (ws < 0)
 5             //恢复成初始状态
 6             compareAndSetWaitStatus(node, ws, 0);
 7         Node s = node.next;
 8         //去除无效节点
 9         if (s == null || s.waitStatus > 0) {
10             s = null;
11             for (Node t = tail; t != null && t != node; t = t.prev)
12                 if (t.waitStatus <= 0)
13                     s = t;
14         }
15         if (s != null)
16             LockSupport.unpark(s.thread);
17     }
18 
19 //脱离队列
20 private void setHead(Node node) {
21         head = node;
22         node.thread = null;
23         node.prev = null;
24     }

6.公平锁和非公平锁实现的区别

  A.公平锁一开始没有抢占操作,而是直接进入acquire()方法

  B.多了一个队列中有没有等待线程的判断

7.AQS队列是一个双向链表

01ReentrantLock

上一篇:若依框架-字段绑定到字典


下一篇:572. 另一棵树的子树