java自旋鎖

來源:互聯網
上載者:User

標籤:limit   變數   廣播   cte   style   reference   改進   set   mit   

一 Test-and-Set Lock

所謂測試設定是最基本的鎖,每個線程共用一把鎖,進入臨界區之前看沒有有線程在臨界區,如果沒有,則進入,並上鎖,如果有則等待。java實踐中利用了原子的設定state變數來保證一次只有一個線程可以獲得到鎖。

public class TASLock implements Lock {    AtomicBoolean state = new AtomicBoolean(false);    @Override    public void lock() {        while (state.getAndSet(true)) {                    }                }    @Override    public void unlock() {        state.set(false);    }}

這種鎖優點就是簡單,缺點是在硬體層面上讀取state時候,如果在cache中命中,那麼直接從cache中讀取就行。但是沒有命中,那麼將在匯流排產生一個廣播,如果在其他處理器中的cache中找到該地址,那麼就以該地址的值做為響應,並且廣播該值。更糟糕的是每一個進入自旋的線程都會產生cache缺失,這樣產生大量廣播流量,延遲較長。

二 指數後退lock

TASLock如果產生大量自旋的線程,則效率很低,避免這個問題就是給後進入自旋的線程一個延遲避讓。避讓策略有很多種,這裡選擇指數回退。

class Backoff {    int max;    int min;    int limit;    public Backoff(int min, int max, int limit) {        this.max = max;        this.min = min;        this.limit = limit;    }    public void backoff() {        int delay = new Random().nextInt(limit);        limit = Math.min(max, 2 * limit);        try {            Thread.sleep(delay);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}public class BackoffLock implements Lock{    private AtomicBoolean state = new AtomicBoolean(false);    @Override    public void lock() {        Backoff backoff = new Backoff(1000, 5000, 100);        while (true) {            while (state.get()) {};            if (!state.getAndSet(true)) {                return;            } else {                backoff.backoff();            }        }    }    @Override    public void unlock() {        state.set(false);    }}
三 基於數組的簡單隊列鎖

上面基於TAS的lock並沒有真正解決cache缺失的流量問題,所以利用java的ThreadLocal為每一個線程儲存一個本地標識索引對應於是否進入臨界區而不是在共用的變數上自旋,這樣cache流量問題就能得到解決。

public class Alock implements Lock {    ThreadLocal<Integer> mysolitindex = new ThreadLocal<Integer>() {        protected Integer initvalue() {            return 0;        }    };    AtomicInteger tail;    boolean[] flag;    int size;    Alock (int capacity) {        size = capacity;        tail = new AtomicInteger(0);        flag = new boolean[capacity];        flag[0] = true;    }    @Override    public void lock() {        int solt = tail.getAndIncrement() % size;        mysolitindex.set(solt);        while (!flag[solt]) {};    }}
四 改進的Alock--CLH隊列鎖

ALock缺點在於並發線程數量固定,空間開銷比較大,每次必須分配固定數量的本地線程變數和共用變數。CLHlock解決了空間問題,它利用threadlocal保持2個指標指向pre和current來實現一個隱式的鏈表,並且通過pre使得cache命中率提高。

class CLHLock implements Lock { AtomicReference<Qnode> tail;  ThreadLocal<Qnode> myNode    = new Qnode(); public void lock() {  Qnode pred     = tail.getAndSet(myNode);  while (pred.locked) {} }}public void unlock() {  myNode.locked.set(false);  myNode = pred; }}

class Qnode { AtomicBoolean locked =   new AtomicBoolean(true);}

本地線程中保持這指向qnode的指標mynode。如果有L個鎖,n個線程,並且每個線程最多同時訪問一個鎖,那麼需要O(L+n)空間。

java自旋鎖

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.