1 Overview java
若是查看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。 spa
wait() 方法被調用後,會執行以下操做: .net
notify()方法被調用後,會執行以下操做: 線程
notifyAll()方法被調用後的操做和notify()相似,不一樣的只是等待集合中全部的線程(同時)都要執行那些操做。然而等待集合中的線程必需要在競爭到目標對象的同步鎖以後,才能繼續執行。 對象
LockSupport類中比較重要的方法有以下幾個: blog
其中park()和park(Object blocker)方法用於block當前線程,unpark(Thread thread)方法用於unblock制定的線程。 跟Thread.suspend()和Thread.resume()不一樣的是,LockSupport經過許可(permit)機制保證:若是當前線程擁有許可,那麼park系列方法會消費掉該許可,而且當即返回(不會被阻塞)。也就是說以下代碼在執行的時候,不會被阻塞: 繼承
須要注意的是:許可不會被累計。也就是說在park調用以前的屢次unpark調用,只會unblock一次park調用。即如下代碼會被阻塞: 文檔
關於park()和park(Object blocker)的區別,Object blocker參數的做用在於容許記錄當前線程被阻塞的緣由,以便監控分析工具進行分析。官方的文檔中也更建議使用park(Object blocker)。此外,跟Object.wait()方法同樣,park系列方法也會由於僞喚醒的緣由返回。