<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ![](https://cdn.zimug.com/wx-zimug.png) [TOC] ## 一、相似之處:Lock鎖 vs Synchronized 代碼塊 Lock鎖是一種類似于synchronized 同步代碼塊的線程同步機制。從Java 5開始`java.util.concurrent.locks`引入了若干個Lock鎖的實現類,所以通常情況下我們不需要實現自己的鎖,重要的是需要知道如何使用它們,了解它們實現背后的原理。 Lock鎖API的基本使用方法和Synchronized 關鍵字大同小異,代碼如下 ~~~ Lock lock = new ReentrantLock(); //實例化鎖 //lock.lock(); //上鎖 boolean locked = lock.tryLock(); //嘗試上鎖 if(locked){ try { //被鎖定的同步代碼塊,同時只能被一個線程執行 }finally { lock.unlock(); //放在finally代碼塊中,保證鎖一定會被釋放 } } ~~~ ~~~ synchronized(obj){ //被鎖定的同步代碼塊,同時只能被一個線程執行 } ~~~ Lock鎖使用看上去麻煩一點,但是java默認提供了很多Lock鎖,能滿足更多的應用場景。比如:基于信號量加鎖、讀寫鎖等等,關注我的專欄[《java并發編程》](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU0NDU5MTk1MQ==&action=getalbum&album_id=1576334194996232194#wechat_redirect),后續都會介紹。 ## 二、Lock接口中的方法 Lock接口實現方法通常會維護一個計數器,當計數器=0的時候資源被釋放,當計數器大于1的時候資源被鎖定。 ~~~ public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition(); } ~~~ * lock() - 調用該方法會使鎖定計數器增加1,如果此時共享資源是空閑的,則將鎖交給調用該方法的線程。 * unlock() - 調用該方法使鎖定計數器減少1,當鎖定計數器為0時,資源被釋放。 * tryLock() - 如果該資源是空閑的,那么調用該方法將返回true,鎖定計數器將增加1。如果資源處于被占用狀態,那么該方法返回false,但是線程將不被阻塞。 * tryLock(long timeout, TimeUnit unit) - 按照該方法嘗試獲得鎖,如果資源此時被占用,線程在退出前等待一定的時間段,該時間段由該方法的參數定義,以期望在此時間內獲得資源鎖。 * lockInterruptibly() - 如果資源是空閑的,該方法會獲取鎖,同時允許線程在獲取資源時被其他線程打斷。這意味著,如果當前線程正在等待一個鎖,但其他線程要求獲得該鎖,那么當前線程將被中斷,并立即返回不會獲得鎖。 ## 三、不同點:Lock鎖 vs Synchronized 代碼塊 使用synchronized同步塊和使用Lock API 之間還是有一些區別的 * 一個synchronized同步塊必須完全包含在一個方法中 - 但Lock API的lock()和unlock()操作,可以在不同的方法中進行 * synchronized同步塊不支持公平性原則,任何線程都可以在釋放后重新獲得鎖,不能指定優先級。但我們可以通過指定fairness 屬性在Lock API中實現公平的優先級,可以實現等待時間最長的線程被賦予對鎖的占有權。 * 如果一個線程無法訪問synchronized同步塊,它就會被阻塞等待。Lock API提供了tryLock()方法,嘗試獲取鎖對象,獲取到鎖返回true,否則返回false。返回false并不阻塞線程,所以使用該方法可以減少等待鎖的線程的阻塞時間。 ## 四、鎖的可重入性 ”可重入“意味著某個線程可以安全地多次獲得同一個鎖對象,而不會造成死鎖。 ### 4.1. synchronized鎖的可重入性 下面的代碼synchronized代碼塊嵌套synchronized代碼塊,鎖定同一個this對象,不會產生死鎖。證明**synchronized代碼塊針對同一個對象加鎖,是可重入的**。 ~~~ public void testLock(){ synchronized (this) { System.out.println("第1次獲取鎖,鎖對象是:" + this); int index = 1; do { synchronized (this) { System.out.println("第" + (++index) + "次獲取鎖,鎖對象是:" + this); } } while (index != 10); } } ~~~ 上面的這段代碼輸出結果是 ~~~ 第1次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第2次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第3次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第4次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第5次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第6次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第7次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第8次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第9次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 第10次獲取鎖,鎖對象是:com.example.demo.thread.TestLockReentrant@769c9116 ~~~ ### 4.2.ReentrantLock可重入鎖 Lock接口的實現類ReentrantLock,也是可重入鎖。一般來說類名包含Reentrant的Lock接口實現類實現的鎖都是可重入的。 ~~~ public void testLock1(){ Lock lock = new ReentrantLock(); //實例化鎖 lock.lock(); //上鎖 System.out.println("第1次獲取鎖,鎖對象是:" + lock); try { int index = 1; do { lock.lock(); //上鎖 try { System.out.println("第" + (++index) + "次獲取鎖,鎖對象是:" + lock); }finally { lock.unlock(); } } while (index != 10); }finally { lock.unlock(); //放在finally代碼塊中,保證鎖一定會被釋放 } } ~~~ 當線程第一次獲得鎖的時候,計數器被設置為1。在解鎖之前,**該線程可以再次獲得鎖**,每次計數器都會增加1。對于每一個解鎖操作,計數器被遞減1,當計數器為0時鎖定資源被釋放。所以最重要的是:**lock(tryLock)要與unlock方法成對出現,即:在代碼中加鎖一次就必須解鎖一次,否則就死鎖** ## 五、Lock鎖的公平性 Java的synchronized 同步塊對試圖進入它們的線程,被授予訪問權(占有權)的優先級順序沒有任何保證。因此如果許多線程不斷爭奪對同一個synchronized 同步塊的訪問權,就有可能有一個或多個線程從未被授予訪問權。這就造成了所謂的 "**線程饑餓**"。為了避免這種情況,鎖應該是公平的。 ~~~ Lock lock = new ReentrantLock(true); ~~~ 可重入鎖提供了一個公平性參數fairness ,通過該參數Lock鎖將遵守鎖請求的順序,即在一個線程解鎖資源后,鎖將被交給等待時間最長的線程。這種公平模式是通過在鎖的構造函數中傳遞 "true "來設置的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看