Java能使得線程阻塞的基礎(chǔ)工具(其余能阻塞線程的方法都是基于它們的)有4種:
- synchronized關(guān)鍵字
控制對資源的同步訪問,如果另一個線程已經(jīng)持有了對象鎖,那么嘗試獲取鎖的線程將被阻塞,并且線程的狀態(tài)會變?yōu)?strong>BLOCKED。 - Object.wait:
當(dāng)線程調(diào)用wait()方法時,它必須持有該對象的鎖。wait()會釋放鎖。這時線程的狀態(tài)將變?yōu)?strong>WAITING(或在使用wait(long timeout)時變?yōu)?strong>TIMED_WAITING)。線程會保持等待狀態(tài)直到被notify()或notifyAll()喚醒,或是等待超時。 - LockSupport.park和LockSupport.parkNanos:
LockSupport.park()和相關(guān)方法使線程進入阻塞狀態(tài),直到它接收到一個“許可”(從其他線程調(diào)用unpark()),或者有其他中斷。在使用LockSupport阻塞時,線程的狀態(tài)是WAITING或TIMED_WAITING(如果使用了parkNanos()或parkUntil()方法的話)。 - Thread.sleep(long millis)
其中Thread.sleep(long millis)是打醬油的,不涉及線程的同步或協(xié)作,一般只用于示例、教學(xué)代碼或測試代碼中。所以我們主要關(guān)注另外3種即可。
為啥有了Object.wait()還需要LockSupport.park()呢?
因為Object.wait()只能在synchronized同步塊中使用,而LockSupport.park()則更靈活,沒有必須在同步塊中使用的限制條件。
Lock、Condition、BlockingQueue、Semaphore、CountDownLatch、CyclicBarrier等都是使用LockSupport.park()來阻塞線程。
synchronized、Object.wait()和Lock、Condition.await()這兩套怎么選?
阻塞在一個條件上,選synchronized、Object.wait(),代碼寫起來更簡潔。
阻塞在多個條件上,沒得選,必須用Lock、Condition.await()。