1. Wait/notify與Condition.await /condition.signal /Condition.signalAll
一個Condition和一個Lock關聯在一起,就想一個條件隊列和一個內建鎖相關聯一樣。要建立一個Condition,可以在相關聯的Lock上調用Lock.newCondition方法。正如Lock比內建加鎖提供了更為豐富的功能,Condition同樣比內建條件隊列提供了更豐富的功能:在每個鎖上可存在多個等待、條件等待可以是可中斷的或者不可中斷的、基於時限的等待,以及公平的或非公平的隊列操作。與內建條件隊列不同的是,對於每個Lock,可以有任意數量的Condition對象。Condition對象繼承了相關的Lock對象的公平性,對於公平的鎖,線程會依照FIFO順序從Condition.await中釋放。
注意:在Condition對象中,與wait,notify和notifyAll方法對於的分別是await,signal,signalAll。但是,Condition對Object進行了擴充,因而它也包含wait和notify方法。一定要確保使用的版本——await和signal.
Condition的作用是對鎖進行更精確的控制。Condition中的await()方法相當於Object的wait()方法,Condition中的signal()方法相當於Object的notify()方法,Condition中的signalAll()相當於Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步鎖"(synchronized關鍵字)捆綁使用的;而Condition是需要與"互斥鎖"/"共用鎖定"捆綁使用的。
2. 如何避免死結
死結是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。這是一個嚴重的問題,因為死結會讓你的程式掛起無法完成任務,死結的發生必須滿足以下四個條件:
互斥條件:一個資源每次只能被一個進程使用。
請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
迴圈等待條件:若干進程之間形成一種頭尾相接的迴圈等待資源關係。
避免死結最簡單的方法就是阻止迴圈等待條件,將系統中所有的資源設定標誌位、排序,規定所有的進程申請資源必須以一定的順序(升序或降序)做操作來避免死結。
3. 有三個線程T1,T2,T3,怎麼確保它們按順序執行
在多線程中有多種方法讓線程按特定順序執行,你可以用線程類的join()方法在一個線程中啟動另一個線程,另外一個線程完成該線程繼續執行。為了確保三個線程的順序你應該先啟動最後一個(T3調用T2,T2調用T1),這樣T1就會先完成而T3最後完成。
如果一個線程A執行了thread.join()語句,其含義是:當前線程A等待thread線程終止之後才從thread.join()返回。join與synchronized的區別是:join在內部使用wait()方法進行等待,而synchronized關鍵字使用的是“對象監視器”做為同步。
join提供了另外兩種實現方法:join(long millis)和join(long millis, int nanos),至多等待多長時間而退出等待(釋放鎖),退出等待之後還可以繼續運行。內部是通過wait方法來實現的。
4. 如果你提交任務時,線程池隊列已滿。會時發會生什麼
這個問題問得很狡猾,許多程式員會認為該任務會阻塞直到線程池隊列有空位。事實上如果一個任務不能被調度執行那麼ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException異常。
5. Java線程池中submit() 和 execute()方法有什麼區別
兩個方法都可以向線程池提交任務,execute()方法的傳回型別是void,它定義在Executor介面中,而submit()方法可以返回持有計算結果的Future對象,它定義在ExecutorService介面中,它擴充了Executor介面,其它線程池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。
6. 如何在Java中建立Immutable對象。
這個問題看起來和多線程沒什麼關係, 但不變性有助於簡化已經很複雜的並發程式。Immutable對象可以在沒有同步的情況下共用,降低了對該對象進行並發訪問時的同步化開銷。可是Java沒有@Immutable這個註解符,要建立不可變類,要實現下面幾個步驟:通過構造方法初始化所有成員、對變數不要提供setter方法、將所有的成員聲明為私人的,這樣就不允許直接存取這些成員、在getter方法中,不要直接返回對象本身,而是複製對象,並返回對象的拷貝。
7. yield方法
yield()方法的作用是放棄當前的CPU資源,將它讓給其他的任務去佔用CPU執行時間。但放棄時間不確定,有可能剛剛放棄,馬上又獲得CPU時間片。這裡需要注意的是yield()方法和sleep方法一樣,線程並不會讓出鎖,和wait不同。
8. 守護線程
Java中有兩種線程,一種是使用者線程,另一種是守護線程。當進程中不存在非守護線程了,則守護線程自動銷毀。通過setDaemon(true)設定線程為後台線程。注意thread.setDaemon(true)必須在thread. Start()之前設定,否則會報IllegalThreadStateException異常;在Daemon線程中產生的新線程也是Daemon的;在使用ExecutorSerice等多線程架構時,會把守護線程轉換為使用者線程,並且也會把優先順序設定為Thread.NORM_PRIORITY。在構建Daemon線程時,不能依靠finally塊中的內容來確保執行關閉或清理資源的邏輯。
9. 安全執行緒的非阻塞隊列
非阻塞隊列有ConcurrentLinkedQueue, ConcurrentLinkedDeque。元素不能為null。以ConcurrentLinkedQueue為例,有頭head和尾tail兩個指標,遵循FIFO的原則進行入隊和出隊,方法有add(E e), peek()取出不刪除, poll()取出刪除, remove(Object o),size(), contains(Objecto), addAll(Collection c), isEmpty()。ConcurrentLinkedDeque是雙向隊列,可以在頭和尾兩個方向進行相應的操作。
10. 阻塞隊列
ArrayBlockingQueue:一個由數組結構組成的有界阻塞隊列。
LinkedeBlockingQueue:一個有鏈表結構組成的有界阻塞隊列。
PriorityBlockingQueue:一個支援優先順序排序的無界阻塞隊列
DelayQueue:一個使用優先順序隊列實現的無界阻塞隊列。
SynchronousQueue:一個不儲存元素的阻塞隊列。
LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。
LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。
見串連:http://www.cnblogs.com/dolphin0520/p/3932906.html
11. Happens-Before規則
程式順序規則:如果程式中操作A在操作B之前,那麼線上程中A操作將在B操作之前。
監視器鎖規則:一個unlock操作現行發生於後面對同一個鎖的lock操作。
volatile變數規則:對一個volatile變數的寫操作先行發生於後面對這個變數的讀操作,這裡的“後面”同樣是指時間上的先後順序。
線程啟動規則:Thread對象的start()方法先行發生於此線程的每一個動作。
線程終止規則:線程的所有操作都先行發生於對此線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的傳回值等於段檢測到線程已經終止執行。
線程中斷規則:線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生。
終結器規則:對象的建構函式必須在啟動該對象的終結器之前執行完成。
傳遞性:如果操作A先行發生於操作B,操作B先行發生於操作C,那就可以得出操作A先行發生於操作C的結論。
12. 如何避免死結
死結是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,他們都將無法推進下去。這是一個嚴重的問題,因為死結會讓你的程式掛起無法完成任務,死結的發生必須滿足一下4個條件:
互斥條件:一個資源每次只能被一個進程使用。
請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
不剝奪條件:進程已獲得的資源,在未使用完之前,不能強行剝奪。
迴圈等待條件:若干進程之間形成一種頭尾相接的迴圈等待資源關係。
避免死結最簡單的方法就是阻止迴圈等待條件,將系統中所有的資源設定標誌位、排序,規定所有的進程申請資源必須以一定的順序做操作來避免死結。
1. 多線程之間如何進行資訊互動
2. 如何停止一個線程
3. 什麼是安全執行緒、如何保證
4. Sleep和wait的區別