<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0
    轉自:http://coderbee.net/index.php/concurrent/20131115/577

    自旋鎖(Spin lock)

    自旋鎖是指當一個線程嘗試獲取某個鎖時,如果該鎖已被其他線程占用,就一直循環檢測鎖是否被釋放,而不是進入線程掛起或睡眠狀態。

    自旋鎖適用于鎖保護的臨界區很小的情況,臨界區很小的話,鎖占用的時間就很短。

    簡單的實現

    import java.util.concurrent.atomic.AtomicReference;

    public class SpinLock {
        
    private AtomicReference<Thread> owner = new AtomicReference<Thread>();
        
        
    public void lock() {
            Thread currentThread 
    = Thread.currentThread();// 如果鎖未被占用,則設置當前線程為鎖的擁有者
            while (owner.compareAndSet(null, currentThread)) { }
        }
        
        
    public void unlock() {
            Thread currentThread 
    = Thread.currentThread();// 只有鎖的擁有者才能釋放鎖
            owner.compareAndSet(currentThread, null);
        }
    }


    SimpleSpinLock里有一個owner屬性持有鎖當前擁有者的線程的引用,如果該引用為null,則表示鎖未被占用,不為null則被占用。

    這里用AtomicReference是為了使用它的原子性的compareAndSet方法(CAS操作),解決了多線程并發操作導致數據不一致的問題,確保其他線程可以看到鎖的真實狀態

    缺點

    1. CAS操作需要硬件的配合;
    2. 保證各個CPU的緩存(L1、L2、L3、跨CPU Socket、主存)的數據一致性,通訊開銷很大,在多處理器系統上更嚴重;
    3. 沒法保證公平性,不保證等待進程/線程按照FIFO順序獲得鎖。

    Ticket Lock

    Ticket Lock 是為了解決上面的公平性問題,類似于現實中銀行柜臺的排隊叫號:鎖擁有一個服務號,表示正在服務的線程,還有一個排隊號;每個線程嘗試獲取鎖之前先拿一個排隊號,然后不斷輪詢鎖的當前服務號是否是自己的排隊號,如果是,則表示自己擁有了鎖,不是則繼續輪詢。

    當線程釋放鎖時,將服務號加1,這樣下一個線程看到這個變化,就退出自旋。

    簡單的實現

    import java.util.concurrent.atomic.AtomicInteger;  

    public class TicketLock {
        
    private AtomicInteger serviceNum = new AtomicInteger(); // 服務號
        private AtomicInteger ticketNum = new AtomicInteger(); // 排隊號
        public int lock() { // 首先原子性地獲得一個排隊號
            int myTicketNum = ticketNum.getAndIncrement(); // 只要當前服務號不是自己的就不斷輪詢
            while (serviceNum.get() != myTicketNum) { }
            
    return myTicketNum;
        }
        
        
    public void unlock(int myTicket) { // 只有當前線程擁有者才能釋放鎖
            int next = myTicket + 1;
            serviceNum.compareAndSet(myTicket, next);
        }
    }

    缺點

    Ticket Lock 雖然解決了公平性的問題,但是多處理器系統上,每個進程/線程占用的處理器都在讀寫同一個變量serviceNum ,每次讀寫操作都必須在多個處理器緩存之間進行緩存同步,這會導致繁重的系統總線和內存的流量,大大降低系統整體的性能。

    下面介紹的CLH鎖和MCS鎖都是為了解決這個問題的。

    MCS 來自于其發明人名字的首字母: John Mellor-Crummey和Michael Scott。

    CLH的發明人是:Craig,Landin and Hagersten。

    MCS鎖

    MCS Spinlock 是一種基于鏈表的可擴展、高性能、公平的自旋鎖,申請線程只在本地變量上自旋,直接前驅負責通知其結束自旋,從而極大地減少了不必要的處理器緩存同步的次數,降低了總線和內存的開銷。

    import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

    public class MCSLock {
        
    public static class MCSNode {
            
    volatile MCSNode next;
            
    volatile boolean isBlock = true// 默認是在等待鎖
        }

        
    volatile MCSNode queue;// 指向最后一個申請鎖的MCSNode
        private static final AtomicReferenceFieldUpdater UPDATER = AtomicReferenceFieldUpdater
                .newUpdater(MCSLock.
    class, MCSNode.class"queue");

        
    public void lock(MCSNode currentThread) {
            MCSNode predecessor 
    = UPDATER.getAndSet(this, currentThread);// step 1
            if (predecessor != null) {
                predecessor.next 
    = currentThread;// step 2

                
    while (currentThread.isBlock) {// step 3
                }
            }
        }

        
    public void unlock(MCSNode currentThread) {
            
    if (currentThread.isBlock) {// 鎖擁有者進行釋放鎖才有意義
                return;
            }

            
    if (currentThread.next == null) {// 檢查是否有人排在自己后面
                if (UPDATER.compareAndSet(this, currentThread, null)) {// step 4
                    
    // compareAndSet返回true表示確實沒有人排在自己后面
                    return;
                } 
    else {
                    
    // 突然有人排在自己后面了,可能還不知道是誰,下面是等待后續者
                    
    // 這里之所以要忙等是因為:step 1執行完后,step 2可能還沒執行完
                    while (currentThread.next == null) { // step 5
                    }
                }
            }

            currentThread.next.isBlock 
    = false;
            currentThread.next 
    = null;// for GC
        }
    }

    CLH鎖

    CLH鎖也是一種基于鏈表的可擴展、高性能、公平的自旋鎖,申請線程只在本地變量上自旋,它不斷輪詢前驅的狀態,如果發現前驅釋放了鎖就結束自旋。

    import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

    public class CLHLock {
        
    public static class CLHNode {
            
    private boolean isLocked = true// 默認是在等待鎖
        }

        @SuppressWarnings(
    "unused" )
        
    private volatile CLHNode tail ;
        
    private static final AtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater
                      . newUpdater(CLHLock.
    class, CLHNode .class , "tail" );

        
    public void lock(CLHNode currentThread) {
            CLHNode preNode 
    = UPDATER.getAndSet( this, currentThread);
            
    if(preNode != null) {//已有線程占用了鎖,進入自旋
                while(preNode.isLocked ) {
                }
            }
        }

        
    public void unlock(CLHNode currentThread) {
            
    // 如果隊列里只有當前線程,則釋放對當前線程的引用(for GC)。
            if (!UPDATER .compareAndSet(this, currentThread, null)) {
                
    // 還有后續線程
                currentThread. isLocked = false ;// 改變狀態,讓后續線程結束自旋
            }
        }
    }


    CLH鎖 與 MCS鎖 的比較

    下圖是CLH鎖和MCS鎖隊列圖示:
    CLH-MCS-SpinLock

    差異:

    1. 從代碼實現來看,CLH比MCS要簡單得多。
    2. 從自旋的條件來看,CLH是在本地變量上自旋,MCS是自旋在其他對象的屬性。
    3. 從鏈表隊列來看,CLH的隊列是隱式的,CLHNode并不實際持有下一個節點;MCS的隊列是物理存在的。
    4. CLH鎖釋放時只需要改變自己的屬性,MCS鎖釋放則需要改變后繼節點的屬性。

    注意:這里實現的鎖都是獨占的,且不能重入的。

    posted on 2015-08-07 00:18 DLevin 閱讀(1131) 評論(0)  編輯  收藏 所屬分類: 收藏MultiThreading
    主站蜘蛛池模板: 114级毛片免费观看| 日本道免费精品一区二区| 国产精品免费观看久久| 亚洲视频在线一区二区三区| 亚洲视频免费在线播放| 99re6免费视频| 亚洲成人网在线观看| 日本XXX黄区免费看| 亚洲色在线无码国产精品不卡 | 在线A亚洲老鸭窝天堂| 又粗又长又爽又长黄免费视频| 99精品视频免费在线观看| 国产自产拍精品视频免费看| 亚洲第一成年男人的天堂| 99免费在线观看视频| 亚洲Av无码乱码在线播放| 九九久久国产精品免费热6| 综合亚洲伊人午夜网 | 成人免费观看男女羞羞视频| 国产日产亚洲系列| 香港a毛片免费观看| va亚洲va日韩不卡在线观看| 国产精品免费看久久久香蕉| 在线免费观看一区二区三区| 亚洲午夜精品一区二区| 久久99九九国产免费看小说| 精品女同一区二区三区免费播放| 99免费观看视频| 亚洲一卡2卡三卡4卡无卡下载| 无码午夜成人1000部免费视频| 精品亚洲一区二区三区在线观看 | 国产精品亚洲天堂| 国产成A人亚洲精V品无码| 手机看黄av免费网址| 欧亚一级毛片免费看| 久久久久久久亚洲Av无码 | 一区二区免费在线观看| 日韩人妻无码免费视频一区二区三区 | 高潮内射免费看片| 久久精品国产亚洲AV麻豆~| 最近高清中文字幕无吗免费看|