您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“java的CLH隊(duì)列鎖是什么”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
CLH隊(duì)列鎖是一種自旋鎖,提供先來先服務(wù)的公平性。
CLH基于鏈表實(shí)現(xiàn)。線程只是在不斷的自旋,不斷地輪詢前驅(qū)節(jié)點(diǎn)的狀態(tài),如果前驅(qū)節(jié)點(diǎn)釋放了鎖,那么線程結(jié)束自旋。
對于持鎖時間很短的場景,比之間把線程阻塞住具有較高的性能,并能可以保持一定的公平性。
還有搭配自旋次數(shù)做深入的優(yōu)化,使得使用場景更廣,性能更好。
對于特定應(yīng)用場景,使用這種鎖可以提高性能,是一種鎖的優(yōu)化方向。
核心理念就是,不要阻塞線程,用循環(huán)來替換。
一種LCH參考實(shí)現(xiàn)
public class ClhSpinLock implements Lock { /** * 前驅(qū)節(jié)點(diǎn) 每個線程 */ private final ThreadLocal<Node> prev = ThreadLocal.withInitial(Node::new); /** * 當(dāng)前節(jié)點(diǎn) */ private final ThreadLocal<Node> currentThreadNode = ThreadLocal.withInitial(Node::new); /** * 指向隊(duì)列末尾節(jié)點(diǎn) * <p> * 值得注意 這個節(jié)點(diǎn)的默認(rèn)值是false 也就是說 如果前驅(qū)節(jié)點(diǎn)是這個默認(rèn)的節(jié)點(diǎn) 那么它是不會起到鎖的作用 * 即 第一個線程進(jìn)來 執(zhí)行l(wèi)ock()操作之后 立即返回 * <p> * 還有所有就是 所有的線程都共享這個tail引用 * 鏈表推進(jìn)是依靠這個共享的tail */ private final AtomicReference<Node> tail = new AtomicReference<>(new Node()); public ClhSpinLock() { } /** * 1.初始狀態(tài) tail指向一個node(head)節(jié)點(diǎn) * +------+ * | head | <---- tail * +------+ * <p> * 2.lock-thread加入等待隊(duì)列: tail指向新的Node,同時Prev指向tail之前指向的節(jié)點(diǎn) * +----------+ * | Thread-A | * | := Node | <---- tail * | := Prev | -----> +------+ * +----------+ | head | * +------+ * <p> * +----------+ +----------+ * | Thread-B | | Thread-A | * tail ----> | := Node | --> | := Node | * | := Prev | ----| | := Prev | -----> +------+ * +----------+ +----------+ | head | * +------+ * 3.尋找當(dāng)前node的prev-node然后開始自旋 */ @Override public void lock() { // 值得注意的細(xì)節(jié) // 如果是第一個線程進(jìn)來 // 那么pred.locked是false 所以這個線程調(diào)用lock之后就直接返回了 // 第二個線程進(jìn)來之后 它的pred就是第一個線程的 // 之后的線程以此類推 final Node currentThreadNode = this.currentThreadNode.get(); currentThreadNode.locked = true; // 所有線程都通過這個tail的不斷變換去推進(jìn) final Node prev = this.tail.getAndSet(currentThreadNode); // 這個只是滿足每個線程自己prev的設(shè)置 其實(shí)是可以省略掉的 this.prev.set(prev); // 自旋 while (prev.locked) { } } @Override public void unlock() { final Node node = this.currentThreadNode.get(); node.locked = false; this.currentThreadNode.set(this.prev.get()); } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock() { return false; } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public Condition newCondition() { return null; } private static class Node { private volatile boolean locked; } }
相關(guān)的測試代碼
public class ClhSpinLockTest { private static int count = 0; private static void testLock(Lock lock) { try { lock.lock(); System.out.println("任務(wù)啟動線程名稱:" + Thread.currentThread().getName() + " 任務(wù)開始時統(tǒng)計(jì)數(shù):" + count + " 任務(wù)執(zhí)行時間:" + System.currentTimeMillis()); for (int i = 0; i < 100; i++) { count++; } System.out.println("任務(wù)啟動線程名稱:" + Thread.currentThread().getName() + " 任務(wù)結(jié)束時統(tǒng)計(jì)數(shù):" + count); } finally { lock.unlock(); } } public static void main(String[] args) { int workerThreadNums = 5; // 這個鎖是需要每個相關(guān)線程都需要持有的 final ClhSpinLock clhSpinLock = new ClhSpinLock(); // 這個是一個柵欄 目的是等到所有線程都執(zhí)行完 看結(jié)果 final CyclicBarrier cyclicBarrier = new CyclicBarrier(workerThreadNums, () -> System.out.println("最終結(jié)果:" + count)); for (int i = 0; i < workerThreadNums; i++) { new Thread(() -> { testLock(clhSpinLock); try { cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } }).start(); } } }
空間復(fù)雜度低
在不同CPU結(jié)構(gòu)體系下,性能是不同的。
“java的CLH隊(duì)列鎖是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。