九九热这里直有精品,1区二区三区在线播放,玖玖爱在线观看资源,国产aⅴ综合网,午夜福利男女,日本亚洲欧美三级,日韩无码黄色导航,内射少妇13区,中文字幕高清网

您身邊的軟件定制專家--9年開發(fā)經(jīng)驗(yàn)為您護(hù)航

18678812288
0531-88887250

Java多線程系列--“JUC鎖”08之 共享鎖和ReentrantReadWriteLock

文章作者:濟(jì)南軟件開發(fā) 時(shí)間:2016年12月20日

概要

Java的JUC(java.util.concurrent)包中的鎖包括"獨(dú)占鎖"和"共享鎖"。在“Java多線程系列--“JUC鎖”02之 互斥鎖ReentrantLock ”中,對(duì)Java的獨(dú)占鎖進(jìn)行了說明。本章對(duì)Java的“共享鎖”進(jìn)行介紹,JUC中的共享鎖有CountDownLatch, CyclicBarrier, Semaphore, ReentrantReadWriteLock等;本章會(huì)以ReentrantReadWriteLock為藍(lán)本對(duì)共享鎖進(jìn)行說明。內(nèi)容包括:

ReadWriteLock 和 ReentrantReadWriteLock介紹

ReadWriteLock 和 ReentrantReadWriteLock函數(shù)列表

參考代碼(基于JDK1.7.0_40)

  獲取共享鎖

  釋放共享鎖

  公平共享鎖和非公平共享鎖

ReentrantReadWriteLock示例

 

 

 

ReadWriteLock 和 ReentrantReadWriteLock介紹

ReadWriteLock,顧名思義,是讀寫鎖。它維護(hù)了一對(duì)相關(guān)的鎖 — — “讀取鎖”和“寫入鎖”,一個(gè)用于讀取操作,另一個(gè)用于寫入操作。

“讀取鎖”用于只讀操作,它是“共享鎖”,能同時(shí)被多個(gè)線程獲取。

“寫入鎖”用于寫入操作,它是“獨(dú)占鎖”,寫入鎖只能被一個(gè)線程鎖獲取。

注意:不能同時(shí)存在讀取鎖和寫入鎖!

ReadWriteLock是一個(gè)接口。ReentrantReadWriteLock是它的實(shí)現(xiàn)類,ReentrantReadWriteLock包括子類ReadLock和WriteLock。

 

 

 

ReadWriteLock 和 ReentrantReadWriteLock函數(shù)列表

ReadWriteLock函數(shù)列表

 

// 返回用于讀取操作的鎖。

Lock readLock()

// 返回用于寫入操作的鎖。

Lock writeLock()

 

 

ReentrantReadWriteLock函數(shù)列表

 

復(fù)制代碼

// 創(chuàng)建一個(gè)新的 ReentrantReadWriteLock,默認(rèn)是采用“非公平策略”。

ReentrantReadWriteLock()

// 創(chuàng)建一個(gè)新的 ReentrantReadWriteLock,fair是“公平策略”。fair為true,意味著公平策略;否則,意味著非公平策略。

ReentrantReadWriteLock(boolean fair)

 

// 返回當(dāng)前擁有寫入鎖的線程,如果沒有這樣的線程,則返回 null。

protected Thread getOwner()

// 返回一個(gè) collection,它包含可能正在等待獲取讀取鎖的線程。

protected Collection<Thread> getQueuedReaderThreads()

// 返回一個(gè) collection,它包含可能正在等待獲取讀取或?qū)懭腈i的線程。

protected Collection<Thread> getQueuedThreads()

// 返回一個(gè) collection,它包含可能正在等待獲取寫入鎖的線程。

protected Collection<Thread> getQueuedWriterThreads()

// 返回等待獲取讀取或?qū)懭腈i的線程估計(jì)數(shù)目。

int getQueueLength()

// 查詢當(dāng)前線程在此鎖上保持的重入讀取鎖數(shù)量。

int getReadHoldCount()

// 查詢?yōu)榇随i保持的讀取鎖數(shù)量。

int getReadLockCount()

// 返回一個(gè) collection,它包含可能正在等待與寫入鎖相關(guān)的給定條件的那些線程。

protected Collection<Thread> getWaitingThreads(Condition condition)

// 返回正等待與寫入鎖相關(guān)的給定條件的線程估計(jì)數(shù)目。

int getWaitQueueLength(Condition condition)

// 查詢當(dāng)前線程在此鎖上保持的重入寫入鎖數(shù)量。

int getWriteHoldCount()

// 查詢是否給定線程正在等待獲取讀取或?qū)懭腈i。

boolean hasQueuedThread(Thread thread)

// 查詢是否所有的線程正在等待獲取讀取或?qū)懭腈i。

boolean hasQueuedThreads()

// 查詢是否有些線程正在等待與寫入鎖有關(guān)的給定條件。

boolean hasWaiters(Condition condition)

// 如果此鎖將公平性設(shè)置為 ture,則返回 true。

boolean isFair()

// 查詢是否某個(gè)線程保持了寫入鎖。

boolean isWriteLocked()

// 查詢當(dāng)前線程是否保持了寫入鎖。

boolean isWriteLockedByCurrentThread()

// 返回用于讀取操作的鎖。

ReentrantReadWriteLock.ReadLock readLock()

// 返回用于寫入操作的鎖。

ReentrantReadWriteLock.WriteLock writeLock()

復(fù)制代碼

 

 

參考代碼(基于JDK1.7.0_40)

ReentrantReadWriteLock的完整源碼

 

 View Code

 

 

AQS的完整源碼

 

 View Code

 

 

其中,共享鎖源碼相關(guān)的代碼如下:

 

復(fù)制代碼

public static class ReadLock implements Lock, java.io.Serializable {

    private static final long serialVersionUID = -5992448646407690164L;

    // ReentrantReadWriteLock的AQS對(duì)象

    private final Sync sync;

 

    protected ReadLock(ReentrantReadWriteLock lock) {

        sync = lock.sync;

    }

 

    // 獲取“共享鎖”

    public void lock() {

        sync.acquireShared(1);

    }

 

    // 如果線程是中斷狀態(tài),則拋出一場,否則嘗試獲取共享鎖。

    public void lockInterruptibly() throws InterruptedException {

        sync.acquireSharedInterruptibly(1);

    }

 

    // 嘗試獲取“共享鎖”

    public  boolean tryLock() {

        return sync.tryReadLock();

    }

 

    // 在指定時(shí)間內(nèi),嘗試獲取“共享鎖”

    public boolean tryLock(long timeout, TimeUnit unit)

            throws InterruptedException {

        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));

    }

 

    // 釋放“共享鎖”

    public  void unlock() {

        sync.releaseShared(1);

    }

 

    // 新建條件

    public Condition newCondition() {

        throw new UnsupportedOperationException();

    }

 

    public String toString() {

        int r = sync.getReadLockCount();

        return super.toString() +

            "[Read locks = " + r + "]";

    }

}

復(fù)制代碼

說明:

ReadLock中的sync是一個(gè)Sync對(duì)象,Sync繼承于AQS類,即Sync就是一個(gè)鎖。ReentrantReadWriteLock中也有一個(gè)Sync對(duì)象,而且ReadLock中的sync和ReentrantReadWriteLock中的sync是對(duì)應(yīng)關(guān)系。即ReentrantReadWriteLock和ReadLock共享同一個(gè)AQS對(duì)象,共享同一把鎖。

ReentrantReadWriteLock中Sync的定義如下:

 

final Sync sync;

下面,分別從“獲取共享鎖”和“釋放共享鎖”兩個(gè)方面對(duì)共享鎖進(jìn)行說明。

 

 

 

獲取共享鎖

獲取共享鎖的思想(即lock函數(shù)的步驟),是先通過tryAcquireShared()嘗試獲取共享鎖。嘗試成功的話,則直接返回;嘗試失敗的話,則通過doAcquireShared()不斷的循環(huán)并嘗試獲取鎖,若有需要,則阻塞等待。doAcquireShared()在循環(huán)中每次嘗試獲取鎖時(shí),都是通過tryAcquireShared()來進(jìn)行嘗試的。下面看看“獲取共享鎖”的詳細(xì)流程。

 

1. lock()

 

lock()在ReadLock中,源碼如下:

 

public void lock() {

    sync.acquireShared(1);

}

 

 

2. acquireShared()

 

Sync繼承于AQS,acquireShared()定義在AQS中。源碼如下:

 

public final void acquireShared(int arg) {

    if (tryAcquireShared(arg) < 0)

        doAcquireShared(arg);

}

說明:acquireShared()首先會(huì)通過tryAcquireShared()來嘗試獲取鎖。

嘗試成功的話,則不再做任何動(dòng)作(因?yàn)橐呀?jīng)成功獲取到鎖了)。

嘗試失敗的話,則通過doAcquireShared()來獲取鎖。doAcquireShared()會(huì)獲取到鎖了才返回。

 

 

 

3. tryAcquireShared()

 

tryAcquireShared()定義在ReentrantReadWriteLock.java的Sync中,源碼如下:

 

復(fù)制代碼

protected final int tryAcquireShared(int unused) {

    Thread current = Thread.currentThread();

    // 獲取“鎖”的狀態(tài)

    int c = getState();

    // 如果“鎖”是“互斥鎖”,并且獲取鎖的線程不是current線程;則返回-1。

    if (exclusiveCount(c) != 0 &&

        getExclusiveOwnerThread() != current)

        return -1;

    // 獲取“讀取鎖”的共享計(jì)數(shù)

    int r = sharedCount(c);

    // 如果“不需要阻塞等待”,并且“讀取鎖”的共享計(jì)數(shù)小于MAX_COUNT;

    // 則通過CAS函數(shù)更新“鎖的狀態(tài)”,將“讀取鎖”的共享計(jì)數(shù)+1。

    if (!readerShouldBlock() &&

        r < MAX_COUNT &&

        compareAndSetState(c, c + SHARED_UNIT)) {

        // 第1次獲取“讀取鎖”。

        if (r == 0) { 

            firstReader = current;

            firstReaderHoldCount = 1;

        // 如果想要獲取鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程

        } else if (firstReader == current) { 

            firstReaderHoldCount++;

        } else {

            // HoldCounter是用來統(tǒng)計(jì)該線程獲取“讀取鎖”的次數(shù)。

            HoldCounter rh = cachedHoldCounter;

            if (rh == null || rh.tid != current.getId())

                cachedHoldCounter = rh = readHolds.get();

            else if (rh.count == 0)

                readHolds.set(rh);

            // 將該線程獲取“讀取鎖”的次數(shù)+1。

            rh.count++;

        }

        return 1;

    }

    return fullTryAcquireShared(current);

}

復(fù)制代碼

說明:tryAcquireShared()的作用是嘗試獲取“共享鎖”。

如果在嘗試獲取鎖時(shí),“不需要阻塞等待”并且“讀取鎖的共享計(jì)數(shù)小于MAX_COUNT”,則直接通過CAS函數(shù)更新“讀取鎖的共享計(jì)數(shù)”,以及將“當(dāng)前線程獲取讀取鎖的次數(shù)+1”。

否則,通過fullTryAcquireShared()獲取讀取鎖。

 

 

 

4. fullTryAcquireShared()

 

fullTryAcquireShared()在ReentrantReadWriteLock中定義,源碼如下:

 

復(fù)制代碼

final int fullTryAcquireShared(Thread current) {

    HoldCounter rh = null;

    for (;;) {

        // 獲取“鎖”的狀態(tài)

        int c = getState();

        // 如果“鎖”是“互斥鎖”,并且獲取鎖的線程不是current線程;則返回-1。

        if (exclusiveCount(c) != 0) {

            if (getExclusiveOwnerThread() != current)

                return -1;

        // 如果“需要阻塞等待”。

        // (01) 當(dāng)“需要阻塞等待”的線程是第1個(gè)獲取鎖的線程的話,則繼續(xù)往下執(zhí)行。

        // (02) 當(dāng)“需要阻塞等待”的線程獲取鎖的次數(shù)=0時(shí),則返回-1。

        } else if (readerShouldBlock()) {

            // 如果想要獲取鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程

            if (firstReader == current) {

            } else {

                if (rh == null) {

                    rh = cachedHoldCounter;

                    if (rh == null || rh.tid != current.getId()) {

                        rh = readHolds.get();

                        if (rh.count == 0)

                            readHolds.remove();

                    }

                }

                // 如果當(dāng)前線程獲取鎖的計(jì)數(shù)=0,則返回-1。

                if (rh.count == 0)

                    return -1;

            }

        }

        // 如果“不需要阻塞等待”,則獲取“讀取鎖”的共享統(tǒng)計(jì)數(shù);

        // 如果共享統(tǒng)計(jì)數(shù)超過MAX_COUNT,則拋出異常。

        if (sharedCount(c) == MAX_COUNT)

            throw new Error("Maximum lock count exceeded");

        // 將線程獲取“讀取鎖”的次數(shù)+1。

        if (compareAndSetState(c, c + SHARED_UNIT)) {

            // 如果是第1次獲取“讀取鎖”,則更新firstReader和firstReaderHoldCount。

            if (sharedCount(c) == 0) {

                firstReader = current;

                firstReaderHoldCount = 1;

            // 如果想要獲取鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程,

            // 則將firstReaderHoldCount+1。

            } else if (firstReader == current) {

                firstReaderHoldCount++;

            } else {

                if (rh == null)

                    rh = cachedHoldCounter;

                if (rh == null || rh.tid != current.getId())

                    rh = readHolds.get();

                else if (rh.count == 0)

                    readHolds.set(rh);

                // 更新線程的獲取“讀取鎖”的共享計(jì)數(shù)

                rh.count++;

                cachedHoldCounter = rh; // cache for release

            }

            return 1;

        }

    }

}

復(fù)制代碼

說明:fullTryAcquireShared()會(huì)根據(jù)“是否需要阻塞等待”,“讀取鎖的共享計(jì)數(shù)是否超過限制”等等進(jìn)行處理。如果不需要阻塞等待,并且鎖的共享計(jì)數(shù)沒有超過限制,則通過CAS嘗試獲取鎖,并返回1。

 

 

 

5. doAcquireShared()

 

doAcquireShared()定義在AQS函數(shù)中,源碼如下:

 

復(fù)制代碼

private void doAcquireShared(int arg) {

    // addWaiter(Node.SHARED)的作用是,創(chuàng)建“當(dāng)前線程”對(duì)應(yīng)的節(jié)點(diǎn),并將該線程添加到CLH隊(duì)列中。

    final Node node = addWaiter(Node.SHARED);

    boolean failed = true;

    try {

        boolean interrupted = false;

        for (;;) {

            // 獲取“node”的前一節(jié)點(diǎn)

            final Node p = node.predecessor();

            // 如果“當(dāng)前線程”是CLH隊(duì)列的表頭,則嘗試獲取共享鎖。

            if (p == head) {

                int r = tryAcquireShared(arg);

                if (r >= 0) {

                    setHeadAndPropagate(node, r);

                    p.next = null; // help GC

                    if (interrupted)

                        selfInterrupt();

                    failed = false;

                    return;

                }

            }

            // 如果“當(dāng)前線程”不是CLH隊(duì)列的表頭,則通過shouldParkAfterFailedAcquire()判斷是否需要等待,

            // 需要的話,則通過parkAndCheckInterrupt()進(jìn)行阻塞等待。若阻塞等待過程中,線程被中斷過,則設(shè)置interrupted為true。

            if (shouldParkAfterFailedAcquire(p, node) &&

                parkAndCheckInterrupt())

                interrupted = true;

        }

    } finally {

        if (failed)

            cancelAcquire(node);

    }

}

復(fù)制代碼

說明:doAcquireShared()的作用是獲取共享鎖。

它會(huì)首先創(chuàng)建線程對(duì)應(yīng)的CLH隊(duì)列的節(jié)點(diǎn),然后將該節(jié)點(diǎn)添加到CLH隊(duì)列中。CLH隊(duì)列是管理獲取鎖的等待線程的隊(duì)列。

如果“當(dāng)前線程”是CLH隊(duì)列的表頭,則嘗試獲取共享鎖;否則,則需要通過shouldParkAfterFailedAcquire()判斷是否阻塞等待,需要的話,則通過parkAndCheckInterrupt()進(jìn)行阻塞等待。

doAcquireShared()會(huì)通過for循環(huán),不斷的進(jìn)行上面的操作;目的就是獲取共享鎖。需要注意的是:doAcquireShared()在每一次嘗試獲取鎖時(shí),是通過tryAcquireShared()來執(zhí)行的!

 

若讀者對(duì)CLH隊(duì)列,shouldParkAfterFailedAcquire(), parkAndCheckInterrupt()等內(nèi)容的細(xì)節(jié)感興趣,可以參考“Java多線程系列--“JUC鎖”02之 互斥鎖ReentrantLock”。

 

 

 

釋放共享鎖

釋放共享鎖的思想,是先通過tryReleaseShared()嘗試釋放共享鎖。嘗試成功的話,則通過doReleaseShared()喚醒“其他等待獲取共享鎖的線程”,并返回true;否則的話,返回flase。

 

1. unlock()

 

public  void unlock() {

    sync.releaseShared(1);

}

說明:該函數(shù)實(shí)際上調(diào)用releaseShared(1)釋放共享鎖。

 

 

 

2. releaseShared()

 

releaseShared()在AQS中實(shí)現(xiàn),源碼如下:

 

復(fù)制代碼

public final boolean releaseShared(int arg) {

    if (tryReleaseShared(arg)) {

        doReleaseShared();

        return true;

    }

    return false;

}

復(fù)制代碼

說明:releaseShared()的目的是讓當(dāng)前線程釋放它所持有的共享鎖。

它首先會(huì)通過tryReleaseShared()去嘗試釋放共享鎖。嘗試成功,則直接返回;嘗試失敗,則通過doReleaseShared()去釋放共享鎖。

 

 

 

3. tryReleaseShared()

 

tryReleaseShared()定義在ReentrantReadWriteLock中,源碼如下:

 

復(fù)制代碼

protected final boolean tryReleaseShared(int unused) {

    // 獲取當(dāng)前線程,即釋放共享鎖的線程。

    Thread current = Thread.currentThread();

    // 如果想要釋放鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程,

    // 并且“第1個(gè)獲取鎖的線程獲取鎖的次數(shù)”=1,則設(shè)置firstReader為null;

    // 否則,將“第1個(gè)獲取鎖的線程的獲取次數(shù)”-1。

    if (firstReader == current) {

        // assert firstReaderHoldCount > 0;

        if (firstReaderHoldCount == 1)

            firstReader = null;

        else

            firstReaderHoldCount--;

    // 獲取rh對(duì)象,并更新“當(dāng)前線程獲取鎖的信息”。

    } else {

 

        HoldCounter rh = cachedHoldCounter;

        if (rh == null || rh.tid != current.getId())

            rh = readHolds.get();

        int count = rh.count;

        if (count <= 1) {

            readHolds.remove();

            if (count <= 0)

                throw unmatchedUnlockException();

        }

        --rh.count;

    }

    for (;;) {

        // 獲取鎖的狀態(tài)

        int c = getState();

        // 將鎖的獲取次數(shù)-1。

        int nextc = c - SHARED_UNIT;

        // 通過CAS更新鎖的狀態(tài)。

        if (compareAndSetState(c, nextc))

            return nextc == 0;

    }

}

復(fù)制代碼

說明:tryReleaseShared()的作用是嘗試釋放共享鎖。

 

 

 

4. doReleaseShared()

 

doReleaseShared()定義在AQS中,源碼如下:

 

復(fù)制代碼

private void doReleaseShared() {

    for (;;) {

        // 獲取CLH隊(duì)列的頭節(jié)點(diǎn)

        Node h = head;

        // 如果頭節(jié)點(diǎn)不為null,并且頭節(jié)點(diǎn)不等于tail節(jié)點(diǎn)。

        if (h != null && h != tail) {

            // 獲取頭節(jié)點(diǎn)對(duì)應(yīng)的線程的狀態(tài)

            int ws = h.waitStatus;

            // 如果頭節(jié)點(diǎn)對(duì)應(yīng)的線程是SIGNAL狀態(tài),則意味著“頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的線程”需要被unpark喚醒。

            if (ws == Node.SIGNAL) {

                // 設(shè)置“頭節(jié)點(diǎn)對(duì)應(yīng)的線程狀態(tài)”為空狀態(tài)。失敗的話,則繼續(xù)循環(huán)。

                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))

                    continue;

                // 喚醒“頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的線程”。

                unparkSuccessor(h);

            }

            // 如果頭節(jié)點(diǎn)對(duì)應(yīng)的線程是空狀態(tài),則設(shè)置“文件點(diǎn)對(duì)應(yīng)的線程所擁有的共享鎖”為其它線程獲取鎖的空狀態(tài)。

            else if (ws == 0 &&

                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))

                continue;                // loop on failed CAS

        }

        // 如果頭節(jié)點(diǎn)發(fā)生變化,則繼續(xù)循環(huán)。否則,退出循環(huán)。

        if (h == head)                   // loop if head changed

            break;

    }

}

復(fù)制代碼

說明:doReleaseShared()會(huì)釋放“共享鎖”。它會(huì)從前往后的遍歷CLH隊(duì)列,依次“喚醒”然后“執(zhí)行”隊(duì)列中每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的線程;最終的目的是讓這些線程釋放它們所持有的鎖。

 

 

 

公平共享鎖和非公平共享鎖

和互斥鎖ReentrantLock一樣,ReadLock也分為公平鎖和非公平鎖。

 

公平鎖和非公平鎖的區(qū)別,體現(xiàn)在判斷是否需要阻塞的函數(shù)readerShouldBlock()是不同的。

公平鎖的readerShouldBlock()的源碼如下:

 

final boolean readerShouldBlock() {

    return hasQueuedPredecessors();

}

 

 

在公平共享鎖中,如果在當(dāng)前線程的前面有其他線程在等待獲取共享鎖,則返回true;否則,返回false。

非公平鎖的readerShouldBlock()的源碼如下:

 

final boolean readerShouldBlock() {

    return apparentlyFirstQueuedIsExclusive();

}

在非公平共享鎖中,它會(huì)無視當(dāng)前線程的前面是否有其他線程在等待獲取共享鎖。只要該非公平共享鎖對(duì)應(yīng)的線程不為null,則返回true。

 

 

 

ReentrantReadWriteLock示例

復(fù)制代碼

 1 import java.util.concurrent.locks.ReadWriteLock; 

 2 import java.util.concurrent.locks.ReentrantReadWriteLock; 

 3 

 4 public class ReadWriteLockTest1 { 

 5 

 6     public static void main(String[] args) { 

 7         // 創(chuàng)建賬戶

 8         MyCount myCount = new MyCount("4238920615242830", 10000); 

 9         // 創(chuàng)建用戶,并指定賬戶

10         User user = new User("Tommy", myCount); 

11 

12         // 分別啟動(dòng)3個(gè)“讀取賬戶金錢”的線程 和 3個(gè)“設(shè)置賬戶金錢”的線程

13         for (int i=0; i<3; i++) {

14             user.getCash();

15             user.setCash((i+1)*1000);

16         }

17     } 

18 } 

19 

20 class User {

21     private String name;            //用戶名 

22     private MyCount myCount;        //所要操作的賬戶 

23     private ReadWriteLock myLock;   //執(zhí)行操作所需的鎖對(duì)象 

24 

25     User(String name, MyCount myCount) {

26         this.name = name; 

27         this.myCount = myCount; 

28         this.myLock = new ReentrantReadWriteLock();

29     }

30 

31     public void getCash() {

32         new Thread() {

33             public void run() {

34                 myLock.readLock().lock(); 

35                 try {

36                     System.out.println(Thread.currentThread().getName() +" getCash start"); 

37                     myCount.getCash();

38                     Thread.sleep(1);

39                     System.out.println(Thread.currentThread().getName() +" getCash end"); 

40                 } catch (InterruptedException e) {

41                 } finally {

42                     myLock.readLock().unlock(); 

43                 }

44             }

45         }.start();

46     }

47 

48     public void setCash(final int cash) {

49         new Thread() {

50             public void run() {

51                 myLock.writeLock().lock(); 

52                 try {

53                     System.out.println(Thread.currentThread().getName() +" setCash start"); 

54                     myCount.setCash(cash);

55                     Thread.sleep(1);

56                     System.out.println(Thread.currentThread().getName() +" setCash end"); 

57                 } catch (InterruptedException e) {

58                 } finally {

59                     myLock.writeLock().unlock(); 

60                 }

61             }

62         }.start();

63     }

64 }

65 

66 class MyCount {

67     private String id;         //賬號(hào) 

68     private int    cash;       //賬戶余額 

69 

70     MyCount(String id, int cash) { 

71         this.id = id; 

72         this.cash = cash; 

73     } 

74 

75     public String getId() { 

76         return id; 

77     } 

78 

79     public void setId(String id) { 

80         this.id = id; 

81     } 

82 

83     public int getCash() { 

84         System.out.println(Thread.currentThread().getName() +" getCash cash="+ cash); 

85         return cash; 

86     } 

87 

88     public void setCash(int cash) { 

89         System.out.println(Thread.currentThread().getName() +" setCash cash="+ cash); 

90         this.cash = cash; 

91     } 

92 }

復(fù)制代碼

運(yùn)行結(jié)果:

 

復(fù)制代碼

Thread-0 getCash start

Thread-2 getCash start

Thread-0 getCash cash=10000

Thread-2 getCash cash=10000

Thread-0 getCash end

Thread-2 getCash end

Thread-1 setCash start

Thread-1 setCash cash=1000

Thread-1 setCash end

Thread-3 setCash start

Thread-3 setCash cash=2000

Thread-3 setCash end

Thread-4 getCash start

Thread-4 getCash cash=2000

Thread-4 getCash end

Thread-5 setCash start

Thread-5 setCash cash=3000

Thread-5 setCash end

復(fù)制代碼

結(jié)果說明:

(01) 觀察Thread0和Thread-2的運(yùn)行結(jié)果,我們發(fā)現(xiàn),Thread-0啟動(dòng)并獲取到“讀取鎖”,在它還沒運(yùn)行完畢的時(shí)候,Thread-2也啟動(dòng)了并且也成功獲取到“讀取鎖”。

因此,“讀取鎖”支持被多個(gè)線程同時(shí)獲取。

(02) 觀察Thread-1,Thread-3,Thread-5這三個(gè)“寫入鎖”的線程。只要“寫入鎖”被某線程獲取,則該線程運(yùn)行完畢了,才釋放該鎖。

因此,“寫入鎖”不支持被多個(gè)線程同時(shí)獲取。


想要了解更多詳情歡迎來電咨詢18678812288
登陸網(wǎng)址:m.h6244.cn。
聯(lián)系人:王經(jīng)理。

高邮市| 安乡县| 涞源县| 深圳市| 白沙| 天水市| 丹凤县| 通榆县| 芮城县| 金阳县| 通辽市| 舟曲县| 偏关县| 徐汇区| 沛县| 长兴县| 监利县| 长岭县| 揭东县| 千阳县| 榆社县| 康马县| 叙永县| 桐梓县| 凤台县| 名山县| 日喀则市| 濉溪县| 永城市| 通江县| 麻栗坡县| 汉寿县| 周至县| 新宾| 郴州市| 阿拉善右旗| 西城区| 阿尔山市| 台中市| 榆中县| 光泽县|