whitesock

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            10 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks

          Inside AbstractQueuedSynchronizer (1)

          Inside AbstractQueuedSynchronizer (2)

          Inside AbstractQueuedSynchronizer (3)

          Inside AbstractQueuedSynchronizer (4)

          1 Overview

          如果查看ReentrantLock,CountDownLatch,Semaphore,FutureTask,ThreadPoolExecutor的源碼,都會發現有個名叫Sync的靜態內部類,繼承自AbstractQueuedSynchronizer。實際上AbstractQueuedSynchronizer是java.util.concurrent的核心組件之一,它為并發包中的其他synchronizers提供了一組公共的基礎設施。

          2 LockSupport
          在介紹AbstractQueuedSynchronizer之前,首先要介紹一下java.util.concurrent.locks.LockSupport。在LockSupport出現之前,如果要block/unblock某個Thread,除了使用Java語言內置的monitor機制之外,只能通過Thread.suspend()和Thread.resume()。然而Thread.suspend()和Thread.resume()基本上不可用,除了可能導致死鎖之外,它們還存在一個無法解決的競爭條件:如果在調用Thread.suspend()之前調用了Thread.resume(),那么該Thread.resume()調用沒有任何效果。LockSupport最主要的作用,便是通過一個許可(permit)狀態,解決了這個問題。

          那么LockSupport和Java語言內置的monitor機制有什么區別呢?它們的語義是不同的。LockSupport是針對特定Thread來進行block/unblock操作的;wait()/notify()/notifyAll()是用來操作特定對象的等待集合的。為了防止知識生銹,在這里簡單介紹一下Java語言內置的monitor機制(詳見:http://whitesock.iteye.com/blog/162344 )。正如每個Object都有一個鎖, 每個Object也有一個等待集合(wait set),它有wait、notify、notifyAll和Thread.interrupt方法來操作。同時擁有鎖和等待集合的實體,通常被成為監視器(monitor)。每個Object的等待集合是由JVM維護的。等待集合一直存放著那些因為調用對象的wait方法而被阻塞的線程。由于等待集合和鎖之間的交互機制,只有獲得目標對象的同步鎖時,才可以調用它的wait、notify和notifyAll方法。這種要求通常無法靠編譯來檢查,如果條件不能滿足,那么在運行的時候調用以上方法就會導致其拋出IllegalMonitorStateException。

          wait() 方法被調用后,會執行如下操作:

          • 如果當前線程已經被中斷,那么該方法立刻退出,然后拋出一個InterruptedException異常。否則線程會被阻塞。
          • JVM把該線程放入目標對象內部且無法訪問的等待集合中。
          • 目標對象的同步鎖被釋放,但是這個線程鎖擁有的其他鎖依然會被這個線程保留著。當線程重新恢復質執行時,它會重新獲得目標對象的同步鎖。

          notify()方法被調用后,會執行如下操作:

          • 如果存在的話,JVM會從目標對象內部的等待集合中任意移除一個線程T。如果等待集合中的線程數大于1,那么哪個線程被選中完全是隨機的。
          • T必須重新獲得目標對象的同步鎖,這必然導致它將會被阻塞到調用Thead.notify()的線程釋放該同步鎖。如果其他線程在T獲得此鎖之前就獲得它,那么T就要一直被阻塞下去。
          • T從執行wait()的那點恢復執行。

          notifyAll()方法被調用后的操作和notify()類似,不同的只是等待集合中所有的線程(同時)都要執行那些操作。然而等待集合中的線程必須要在競爭到目標對象的同步鎖之后,才能繼續執行。

          LockSupport類中比較重要的方法有如下幾個:

          public static void park() {
              unsafe.park(false, 0L);
          }
          
          public static void park(Object blocker) {
              Thread t = Thread.currentThread();
              setBlocker(t, blocker);
              unsafe.park(false, 0L);
              setBlocker(t, null);
          }
          
          public static void unpark(Thread thread) {
              if (thread != null)
                  unsafe.unpark(thread);
          }

          其中park()和park(Object blocker)方法用于block當前線程,unpark(Thread thread)方法用于unblock制定的線程。 跟Thread.suspend()和Thread.resume()不同的是,LockSupport通過許可(permit)機制保證:如果當前線程擁有許可,那么park系列方法會消費掉該許可,并且立即返回(不會被阻塞)。也就是說如下代碼在執行的時候,不會被阻塞:

          LockSupport.unpark(Thread.currentThread());
          LockSupport.park();

          需要注意的是:許可不會被累計。也就是說在park調用之前的多次unpark調用,只會unblock一次park調用。即以下代碼會被阻塞:

          LockSupport.unpark(Thread.currentThread());
          LockSupport.unpark(Thread.currentThread());
          LockSupport.park();
          LockSupport.park();

          關于park()和park(Object blocker)的區別,Object blocker參數的作用在于允許記錄當前線程被阻塞的原因,以便監控分析工具進行分析。官方的文檔中也更建議使用park(Object blocker)。此外,跟Object.wait()方法一樣,park系列方法也會因為偽喚醒的原因返回。

          posted on 2012-01-06 11:04 whitesock 閱讀(293) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          主站蜘蛛池模板: 太湖县| 柘荣县| 沛县| 通江县| 威远县| 万安县| 塔城市| 霞浦县| 社旗县| 三门县| 莱阳市| 通渭县| 阿合奇县| 朝阳市| 长沙市| 松潘县| 上林县| 资兴市| 安化县| 沂南县| 黄冈市| 建德市| 平谷区| 西昌市| 临沧市| 彭泽县| 元朗区| 雷州市| 尚志市| 康马县| 卢湾区| 深圳市| 扶余县| 延津县| 札达县| 日土县| 泸水县| 安塞县| 长顺县| 略阳县| 策勒县|