main函數是一個線程 t.start開啟了另一個線程。這兩個線程同時在跑,有時候main的線程快,有時候t的線程快。在t.start();后面加上Thread.sleep(1000); 這樣一定是 run.
【Answer】 AF
【例題辨析】 A. 題意:超過兩個線程可能立即出現死鎖。
符合死鎖定義。
B. 題意:Java虛擬機的實現能確保多個線程不會進入死鎖狀態。
Java語言中解決并發(Concurrent)運行沖突并不是由Java虛擬機負責的,而是由應用程序自行處理,比如同步化(Synchronization)等機制都由程序員在應用設計中使用的,所以,Java虛擬機并不能保證不發生死鎖。
C. 題意:只要死鎖線程的sleep()方法睡眠時間期滿,死鎖線程就會獲釋。
這種觀點顯然沒有正確理解Deadlock與sleep之間的區別,死鎖是線程對資源的競爭造成的,線程睡眠期滿并不能保證線程獲得所需資源。
D. 題意:只有當wait()、notify()、notifyAll()這些方法不正確使用時死鎖才發生。
wait()、notify()、notifyAll()這些方法不正確使用時確實可以造成死鎖,但不是死鎖發生的唯一原因,根本原因還是資源競爭,因此別的因素也可以造成死鎖。
E. 題意:只有當同步塊不正確使用時單線程應用才會死鎖。
死鎖是發生在兩個或兩個以上線程之間,既然是單線程應用那就談不上死鎖了。
F. 題意:如果一個程序片斷會死鎖,那么你就不能通過插入Thread.yield()方法調用消除死鎖。
Thread.yield()方法功能是告訴線程調度者當前線程愿意讓出對處理器(CPU)的占用,線程調度者甚至可以不理睬這個方法。造成死鎖的資源不僅是處理器,顯然這種方式并不足以解決死鎖。
(1)線程同步(Thread Synchronization)
線程間通信主要是通過共享字段(Field)或對象引用實現的,這種通信形式雖然高效,但會帶來線程干擾(Thread Interference)和內存不一致的弊端,線程同步機制就是防止這類弊端的機制。不過,線程同步機制又會帶來線程競爭(Thread Contention)問題,即在兩個或兩個以上線程同時訪問同一資源時導致線程阻塞。
(2)內部鎖(Intrinsic Lock),又稱監控鎖(Monitor Lock)
Java同步化機制是圍繞內部鎖建立的,每個對象都擁有唯一的一把內部鎖,當線程需要排他性地訪問某個對象時,這個線程就需要擁有那個對象的內部鎖,一旦這個線程擁有那個對象的內部鎖,其他線程就不能再獲得那把內部鎖,如果其他線程仍試圖去獲取那把內部鎖將會被阻塞。
(3)同步化方法(Synchronized Method)和同步化語句(Synchronized Statement)
Java語言為同步化機制提供了兩種基本形式,即同步化方法(Synchronized Method)和同步化語句(Synchronized Statement)。synchronized是建立同步化方法或語句的關鍵詞。
當一個線程執行一個同步化方法時,線程就默認擁有同步化方法所在對象的內部鎖,其他線程要調用這個對象的同步化方法(即使是不同的同步化方法)時都會被阻塞,直到第一個線程執行完成同步化方法釋放內部鎖后才能再執行這個對象的同步化方法。
同步化語句則是更加靈活的同步化機制,通過synchronized關鍵詞明確指定提供內部鎖的對象,這樣同一個對象中不同的同步化語句塊就可以擁有不同的內部鎖,不同的同步化語句塊就可以讓不同的線程調用執行。
(4)wait()、notify()、notifyAll()方法
1,wait(): 讓線程處于凍結狀態,被wait的線程會被存儲到線程池中。 2,notify():喚醒線程池中一個線程(任意). 3,notifyAll():喚醒線程池中的所有線程。
調用這幾個方法的對象的內部鎖必須被當前線程獲得,如果當前線程不是主調對象內部鎖的擁有者,則會拋出IllegalMonitorStateException。
讓調用這幾個方法的線程擁有主調對象內部鎖的方式,主要有: (a)執行主調對象中同步化實例方法; (b)執行主調對象同步化語句塊; (c)對于Class對象,執行它的同步化靜態方法。
【例題】
void waitForSignal(){ Object obj = new Object(); synchronized (Thread.currentThread()) { obj.wait(); obj.notify(); } }Which statement is true?A. This code can throw anInterruptedException.B. This code can throw anIllegalMonitorStateException.C. This code can throw aTimeoutException after ten minutes.D. Reversing the order ofobj.wait() and obj.notify() might cause this method to complete normally.E. A call to notify() ornotifyAll() from another thread might cause this method to complete normally.F. This code does NOT compileunless "obj.wait()" is replaced with "((Thread)obj).wait()".【Answer】 B
【例題辨析】
(1)wait()和notify()這兩個方法都會拋出IllegalMonitorStateException,這個異常是RuntimeException的子類,屬于unchecked exception,可以不捕捉。但是,wait()方法還會拋出InterruptedException,這個異常必須捕捉,因此程序有編譯錯誤。應該為waitForSignal方法聲明中添加throws InterruptedException: void waitForSignal() throws InterruptedException { ……
或者,為wait()和notify()方法調用語句添加try…catch…
(2)本例中,wait()和notify()方法的主調對象是obj,而obj對象的內部鎖沒有被當前線程取得,不符合wait()、notify()方法的調用條件,因此調用waitForSignal()時,會拋出如下異常:
Exception in thread "main"java.lang.IllegalMonitorStateExceptionatjava.lang.Object.wait(Native Method) atjava.lang.Object.wait(Unknown Source)atExamA_3.waitForSignal(ExamA_3.java:6)atExamA_3.main(ExamA_3.java:13)解決方案是將synchronized (Thread.currentThread())修改為synchronized (obj),這樣當前線程就取得了obj對象的內部鎖。
A. InterruptedException在編譯時就會發現,因此不會在運行時拋出; B. 根據上面分析可知正確; C. 線程死鎖是無法預知時間的; D. 本程序錯誤不在于obj.wait() and obj.notify()調用順序,而是在于當前線程沒有取得obj內部鎖; E. 同上 F. 同上
【例題辨析】 (1)主類Tester實現了線程方法run(),run()的主要工作就是取得當前線程號,main()方法創建了兩個Tester類的線程對象,既然有兩個線程對象,也就意味著run()代碼在內存映像中有兩份,即這兩個run()方法是各自獨立運行在兩個不同線程中,因此,Thread.currentThread().getId()取得的是各自的線程號;
(2)線程號取得后作為參數傳遞給PingPong2類對象pp2的hit()方法,hit()方法負責顯示輸出信息,hit()是同步化方法,也就意味著當某個線程調用它時,另外的線程必須等待它運行結束,才能取得調用hit()的資格。
A. 從輸出信息可以看出,5號線程調用同步化方法hit()時,該方法中循環還未運行結束,6號線程就又調用hit()輸出信息,這違背了同步化方法機制;
B. 從輸出信息可以看出,6號線程調用同步化方法hit()結束后,5號線程才能調用hit()輸出信息,這符合了同步化方法機制;
C. 同A
D. 出現6、5、7三個線程號,顯然不符合本題只有2個線程。
【知識點】 (1)Thread類的start()方法 start()方法用于啟動線程的執行,也就是讓run()方法開始運行。 start()方法只允許執行一次,也就是說一個線程只允許啟動一次,即使執行完畢也不允許重新啟動,否則會拋出IllegalThreadStateException。
public class Threads4 { public static void main (String[] args) { new Threads4().go();}public void go() { Runnable r = new Runnable() { public void run() { System.out.print("foo"); } }; Thread t = new Thread(r); t.start(); t.start(); }}What is the result?A. Compilation fails.B. An exception is thrown at runtime.C. The code executes normally and prints "foo".D. The code executes normally, but nothing is printed.Explanation/Reference:Exception in thread "main" java.lang.IllegalThreadStateExceptionat java.lang.Thread.start(Unknown Source)at Threads4.go(Threads4.java:14)at Threads4.main(Threads4.java:3)foo【答案】B
A. 可以在Eclipse開發環境中嘗試錄入本程序 ,如果編輯窗口中沒有錯誤提示出現,通常不存在編譯錯誤;
B. 同樣,在Eclipse開發環境中嘗試錄入本程序,可以看到如下信息:
fooException in thread “main”Java.lang.IllegalThreadStateException
atjava.lang.Thread.start(Unknown Source) atThreads4.go(Threads4.java:17) atThreads4.main(Threads4.java:5)上述信息說明運行時拋出了異常,這是因為Thread類的start()方法只允許執行一次,也就是說一個線程只允許啟動一次,即使執行完畢也不允許重新啟動;
Answer: BE
新聞熱點
疑難解答