溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java的CLH隊(duì)列鎖是什么

發(fā)布時間:2021-11-15 11:02:51 來源:億速云 閱讀:139 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“java的CLH隊(duì)列鎖是什么”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

是什么

CLH隊(duì)列鎖是一種自旋鎖,提供先來先服務(wù)的公平性。

有什么特點(diǎn)

CLH基于鏈表實(shí)現(xiàn)。線程只是在不斷的自旋,不斷地輪詢前驅(qū)節(jié)點(diǎn)的狀態(tài),如果前驅(qū)節(jié)點(diǎn)釋放了鎖,那么線程結(jié)束自旋。
對于持鎖時間很短的場景,比之間把線程阻塞住具有較高的性能,并能可以保持一定的公平性。
還有搭配自旋次數(shù)做深入的優(yōu)化,使得使用場景更廣,性能更好。

有什么作用

對于特定應(yīng)用場景,使用這種鎖可以提高性能,是一種鎖的優(yōu)化方向。

實(shí)現(xiàn)原理解析

核心理念就是,不要阻塞線程,用循環(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();
        }
    }
}

優(yōu)缺點(diǎn)

  1. 空間復(fù)雜度低

  2. 在不同CPU結(jié)構(gòu)體系下,性能是不同的。

“java的CLH隊(duì)列鎖是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(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)容。

AI