成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

ReentrantLock介紹

ReentrantLock 基于AQS實(shí)現(xiàn)了公平和非公平的獨(dú)占鎖功能。

ReentrantLock定義AQS的同步狀態(tài)(synchronization state)如下:

State為0表示鎖可用;為1表示被占用;為N表示鎖重入的次數(shù),是獨(dú)占資源。

ReentrantLock實(shí)現(xiàn)公平鎖原理

案例代碼如下:

1、啟動(dòng)文件

目前創(chuàng)新互聯(lián)公司已為上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、西盟網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

public class Main {

    public static void main(String[] args) throws ParseException {

        ReentrantLock lock = new ReentrantLock(true);
        Thread t1 = new Thread(new Task(lock),"Thread-1");
        Thread t2 = new Thread(new Task(lock),"Thread-2");
        Thread t3 = new Thread(new Task(lock),"Thread-3");

        t1.start();
        t2.start();
        t3.start();
    }
}

2、Task

import java.util.concurrent.locks.ReentrantLock;

public class Task implements Runnable{

    private ReentrantLock lock;

    public Task(ReentrantLock lock) {
        this.lock = lock;
    }

    @Override
    public void run() {

        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "獲取到鎖....");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "釋放鎖....");
            lock.unlock();
        }
    }
}

3、執(zhí)行結(jié)果:
多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

案例分析

1、Thread-1調(diào)用lock方法

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

ReentrantLock內(nèi)部繼承AQS實(shí)現(xiàn)了1個(gè)抽象類(lèi)Sync

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

繼承于Sync實(shí)現(xiàn)了2個(gè)內(nèi)部類(lèi)FairSync(公平的)和NonfairSync(非公平的)

此時(shí)調(diào)用FairSync的lock方法

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

acquire方法來(lái)自AQS,注意參數(shù)是1

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

tryAcquire是ReentrantLock自己實(shí)現(xiàn)的,嘗試獲取鎖
protected final boolean tryAcquire(int acquires) { //參數(shù)是1
        final Thread current = Thread.currentThread(); //當(dāng)前線(xiàn)程
        int c = getState(); //獲取當(dāng)前同步狀態(tài)
        if (c == 0) { //如果是0,則鎖沒(méi)有被占用
            //等待隊(duì)列中,前面沒(méi)有其他等待的線(xiàn)程,則用CAS的方法更新同步狀態(tài)state
            if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current); //成功的話(huà),則設(shè)置鎖的占有線(xiàn)程為當(dāng)前線(xiàn)程
                return true; //返回獲取資源成功
            }
        }
        //如果鎖已經(jīng)被占用,則判斷是不是自己占用的
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;//如果是自己占用的,則是重入,增加state值,累加1
            if (nextc < 0) //重入次數(shù)過(guò)大,拋出異常
                throw new Error("Maximum lock count exceeded");
            setState(nextc); //設(shè)置state值
            return true; //重入返回ture
        }
        return false;//沒(méi)有獲取資源返回false
    }
Thread-1獲取了鎖資源,沒(méi)有釋放。

2、Thread-2,開(kāi)始請(qǐng)求資源,調(diào)用lock,此時(shí)鎖資源還被Thread-1占用

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

addWaiter方法:
private Node addWaiter(Node mode) {
        //把當(dāng)前線(xiàn)程包裝成節(jié)點(diǎn),準(zhǔn)備放入等待隊(duì)列
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        //嘗試直接把節(jié)點(diǎn)設(shè)置成隊(duì)尾,否則執(zhí)行enq
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;//當(dāng)前節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)是之前的隊(duì)尾節(jié)點(diǎn)
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        //當(dāng)前節(jié)點(diǎn)插入隊(duì)尾
        enq(node);
        return node;
    }
enq自旋+初始化等待隊(duì)列,并返回Thread-2節(jié)點(diǎn)
private Node enq(final Node node) {
        //采用自旋,保證節(jié)點(diǎn)插入
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize 如果隊(duì)列為空,則創(chuàng)建一個(gè)空的節(jié)點(diǎn),設(shè)置為頭尾節(jié)點(diǎn)
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) { //隊(duì)列不為空,追加到隊(duì)尾
                    t.next = node;
                    return t;
                }
            }
        }
    }
然后對(duì)Thread-2包裝節(jié)點(diǎn)執(zhí)行acquireQueued
final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                //判斷節(jié)點(diǎn)的前任節(jié)點(diǎn)是不是頭節(jié)點(diǎn),頭節(jié)點(diǎn)是一個(gè)空節(jié)點(diǎn)
                final Node p = node.predecessor();
                //如果是頭節(jié)點(diǎn),則說(shuō)明當(dāng)前節(jié)點(diǎn)是隊(duì)列里的第一個(gè)節(jié)點(diǎn),首節(jié)點(diǎn)。
                //則嘗試獲取鎖資源,此處因?yàn)門(mén)hread-1占用著資源,則失敗
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //失敗之后,則判斷當(dāng)前節(jié)點(diǎn)線(xiàn)程Thread-2是不是可以阻塞
                if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
是否阻塞shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;//前驅(qū)節(jié)點(diǎn)的狀態(tài)
        if (ws == Node.SIGNAL) //如果是SIGNAL,則說(shuō)明前驅(qū)節(jié)點(diǎn)狀態(tài)可以喚醒后繼節(jié)點(diǎn),可以阻塞
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev; //只有CANCELLED狀態(tài)大于0,則把取消狀態(tài)的節(jié)點(diǎn)從隊(duì)列刪除
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//設(shè)置前驅(qū)節(jié)點(diǎn)為SIGNAL狀態(tài)
        }
        return false;
    }
如果可以阻塞,則調(diào)用parkAndCheckInterrupt,阻塞線(xiàn)程,至此Thread-2進(jìn)入隊(duì)列,并阻塞了,耐心等待

3、Thread-3同Thread-2,略過(guò)

4、Thread-1釋放鎖資源

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

release方法:

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

tryRelease

多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)

然后通過(guò)unparkSuccessor,喚醒首節(jié)點(diǎn),保證公平策略。

至此Thread-1釋放完成,Thread-2可以獲得資源,依次類(lèi)推。

標(biāo)題名稱(chēng):多線(xiàn)程(十、AQS原理-ReentrantLock公平鎖)
文章來(lái)源:http://jinyejixie.com/article8/ppshop.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、建站公司、小程序開(kāi)發(fā)、面包屑導(dǎo)航網(wǎng)站內(nèi)鏈、域名注冊(cè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)
屯昌县| 津南区| 承德市| 丰镇市| 资阳市| 巴林左旗| 厦门市| 和田市| 营山县| 襄城县| 台州市| 鸡泽县| 连州市| 神池县| 邵东县| 逊克县| 石屏县| 孟州市| 玉田县| 政和县| 图木舒克市| 惠东县| 牟定县| 平罗县| 阳原县| 友谊县| 洞口县| 西平县| 綦江县| 广州市| 汕尾市| 新干县| 濮阳市| 宁国市| 焉耆| 南宁市| 安康市| 遂宁市| 台前县| 奇台县| 获嘉县|