MCS鎖和CLH鎖

CLH鎖:自旋鎖,在上一個節點上等待,先上代碼:node

 1 public class CLHLock {
 2     /**
 3      * 保證原子性操做
 4      *
 5      */
 6     private AtomicReference<Node> tail = new AtomicReference<>(new Node());
 7     /**
 8      * 每一個線程的節點變量不一樣
 9      *
10      */
11     private ThreadLocal<Node> current = ThreadLocal.withInitial(() -> new Node());
12     /**
13      * 記錄前驅節點,而且複用此節點來防止死鎖:
14      * 假設不使用該節點的話,有T1,T2兩個線程,T1先lock成功,而後T2調用lock()時會
15      * 自旋在T1的節點的locked字段上,若是當T1線程unlock()以後,(T2還沒獲取到CPU時間片),
16      * T1再次調用lock(),由於此時tail的值是T2線程的節點,其locked值爲true,因此T1自旋等待
17      * T2釋放鎖,而此時的T2還在等T1釋放鎖,這就形成了死鎖。
18      *
19      */
20     private ThreadLocal<Node> pred = new ThreadLocal<>();
21 
22     public void lock() {
23         Node node = current.get();
24         node.locked = true;
25         // 將tail設置爲當前線程的節點,並獲取到上一個節點,此操做爲原子性操做
26         Node preNode = tail.getAndSet(node);
27         pred.set(preNode);
28         // 在前驅節點的locked字段上忙等待
29         while (preNode.locked);
30 
31     }
32 
33 
34     public void unlock() {
35         Node node = current.get();
36         // 將當前線程節點的locked屬性設置爲false,使下一個節點成功獲取鎖
37         node.locked = false;
38         current.set(pred.get());
39     }
40 
41 
42 
43 
44     static class Node{
45         volatile boolean locked;
46     }
47 }

 

 

注意它的實例變量,tail爲一個原子引用,因此在它上的操做都是原子性操做,它是全部線程共享的變量,與後面的兩個變量區分開,current是線程本地變量,它的值都和當前線程有關。current記錄的是當前線程的鎖狀況。spa

加鎖時,現將current的locked屬性設置爲true,表示當前線程須要獲取鎖,而後將tail中的值設置爲當前線程節點,getAndSet方法設置新值並返回以前的值,這樣每一個線程節點之間就有一條隱形的」鏈「關聯着,像一個鏈表。最後在上一個節點的locked屬性上自旋等待。線程

解鎖時,只需把當前節點的locked屬性設置爲false,這樣緊接着的後面一個的線程就會成功的獲取鎖。code

 

MCS鎖:blog

 1 public class MCSLock {
 2     AtomicReference<Node> tail = new AtomicReference<>();
 3     ThreadLocal<Node> current = ThreadLocal.withInitial(() -> new Node());
 4 
 5 
 6     public void lock() {
 7         Node node = current.get();
 8         Node pred = tail.getAndSet(node);
 9         // pred的初始值爲null,因此第一個加鎖線程,直接跳過判斷,加鎖成功
10         // tail中記錄的是當前線程的節點
11         if (pred != null) {
12             pred.next = node;
13             while (node.locked);
14         }
15 
16     }
17 
18     public void unlock() {
19         Node node = current.get();
20         if (node.next == null) {
21             // 若是設置成功,說明在此以前沒有線程進行lock操做,直接return便可;
22             // 若是失敗,則說明在此以前有線程進行lock操做,須要自旋等待那個線程將自身節點設置爲本線程節點的next,
23             // 而後進行後面的操做。
24             if (tail.compareAndSet(node, null))
25                 return;
26             while (node.next == null);
27         }
28         // 通知下一個線程,使下一個線程加鎖成功
29         node.next.locked = false;
30         // 解鎖後須要將節點之間的關聯斷開,不然會產生內存泄露
31         node.next = null;
32     }
33 
34 
35     static class Node{
36         volatile boolean locked = true;
37         volatile Node next;
38     }
39 
40 }

 

CLH和MCS鎖都是自旋鎖,公平鎖(保證FIFO),獨佔鎖,而且是不可重入鎖。他們兩的名字都是發明者的名字的縮寫。內存

相關文章
相關標籤/搜索