lesson3.1:java公平鎖和非公平鎖及讀寫鎖


    關於這四種鎖的各自情況,網上有很多文章做了介紹,本不想單獨開章節介紹,本章只介紹這四種鎖的一些源碼特點及注意事項。

    demo 源碼:https://github.com/mantuliu/javaAdvance

    首先來看公平鎖和非公平鎖,我們默認使用的鎖是非公平鎖,只有當我們顯示設置為公平鎖的情況下,才會使用公平鎖,下面我們簡單看一下公平鎖的源碼,如果等待隊列中沒有節點在等待,則占有鎖,如果已經存在等待節點,則返回失敗,由后面的程序去將此線程加入等待隊列:

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

     通過上面的代碼,我們可以推斷,當使用公平鎖的情況下,並且同一個線程的執行時間較長時,線程內部進行了多次的鎖的獲取和釋放,效率非常低下,可以參加Lesson8中的demo:

demo Lesson8LockIntPerform:在使用ReentrantLock加非公平鎖的情況下100個線程循環下單數為:857239882

demo Lesson8LockIntPerform:在使用ReentrantLock加非公平鎖的情況下100個線程循環下單數為:860364303

demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平鎖的情況下100個線程循環下單數為:19153640

demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平鎖的情況下100個線程循環下單數為:19076567

     上面的demo中,在使用公平鎖的情況下性能明顯降低,非公平鎖的性能是公平鎖性能的幾十倍以上,這和公平鎖每次試圖占有鎖時,都必須先要進等待隊列,按照FIFO的順序去獲取鎖,因此在我們的實驗情景下,使用公平鎖的線程進行了頻繁切換,而頻繁切換線程,性能必然會下降的厲害,這也告誡了我們在實際的開發過程中,在需要使用公平鎖的情景下,務必要考慮線程的切換頻率。

     接下來我們來看一下讀寫鎖,通過看讀寫鎖的實現源碼,我們可以發現,讀鎖和寫鎖共用同一個等待隊列,那么在采用非公平鎖的情況下,如果讀鎖的線程執行時間比較長,並且讀鎖的並發比較高,那么寫鎖的線程便永遠都拿不到鎖,那么實際的情況會不會是這樣呢?

demo Lesson3WriteReadLock:此demo的讀線程在不斷的占用讀鎖,按照推論,寫鎖的線程是沒有機會獲取到鎖的,但是實際情況是寫鎖的線程可以正常的獲取到鎖,那么是什么原因使得寫鎖的線程可以獲取到鎖的了?通過查看源代碼,會發現有這樣的一個方法:

    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }

上面的方法,實現了一個新的讀線程獲取鎖的中斷,它會讀取等待隊列中下一個等待鎖的線程,如果它是獲取寫鎖的線程,那么此方法返回為真,調用它的程序會把這個試圖獲取讀鎖的線程加入到等待隊列,從而終止了讀線程一直都在占有鎖的情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM