Java程序員面試中的多線程問題

學識都 人氣:2.13W

0、Java中多線程同步是什麼?

Java程序員面試中的多線程問題

在多線程程序下,同步能控制對共享資源的訪問。如果沒有同步,當一個Java線程在修改一個共享變量時,另外一個線程正在使用或者更新同一個變量,這樣容易導致程序出現錯誤的結果。

1、解釋實現多線程的幾種方法?

一Java線程可以實現Runnable接口或者繼承Thread類來實現,當你打算多重繼承時,優先選擇實現Runnable。

2、t()與()有什麼區別?

t()方法(native)啓動線程,使之進入就緒狀態,當cpu分配時間該線程時,由JVM調度執行run()方法。

3、爲什麼需要run()和start()方法,我們可以只用run()方法來完成任務嗎?

我們需要run()&start()這兩個方法是因爲JVM創建一個單獨的線程不同於普通方法的調用,所以這項工作由線程的start方法來完成,start由本地方法實現,需要顯示地被調用,使用這倆個方法的另外一個好處是任何一個對象都可以作爲線程運行,只要實現了Runnable接口,這就避免因繼承了Thread類而造成的Java的多繼承問題。

4、什麼是ThreadLocal類,怎麼使用它?

ThreadLocal是一個線程級別的局部變量,並非“本地線程”。ThreadLocal爲每個使用該變量的線程提供了一個獨立的'變量副本,每個線程修改副本時不影響其它線程對象的副本(譯者注)。

下面是線程局部變量(ThreadLocal variables)的關鍵點:

一個線程局部變量(ThreadLocal variables)爲每個線程方便地提供了一個單獨的變量。

ThreadLocal實例通常作爲靜態的私有的(private static)字段出現在一個類中,這個類用來關聯一個線程。

當多個線程訪問ThreadLocal實例時,每個線程維護ThreadLocal提供的獨立的變量副本。

常用的使用可在DAO模式中見到,當DAO類作爲一個單例類時,數據庫鏈接(connection)被每一個線程獨立的維護,互不影響。(基於線程的單例)

5、什麼時候拋出InvalidMonitorStateException異常,爲什麼?

調用wait()/notify()/notifyAll()中的任何一個方法時,如果當前線程沒有獲得該對象的鎖,那麼就會拋出IllegalMonitorStateException的異常(也就是說程序在沒有執行對象的任何同步塊或者同步方法時,仍然嘗試調用wait()/notify()/notifyAll()時)。由於該異常是RuntimeExcpetion的子類,所以該異常不一定要捕獲(儘管你可以捕獲只要你願意).作爲RuntimeException,此類異常不會在wait(),notify(),notifyAll()的方法簽名提及。

6、Sleep()、suspend()和wait()之間有什麼區別?

p()使當前線程在指定的時間處於“非運行”(Not Runnable)狀態。線程一直持有對象的監視器。比如一個線程當前在一個同步塊或同步方法中,其它線程不能進入該塊或方法中。如果另一線程調用了 interrupt()方法,它將喚醒那個“睡眠的”線程。

注意:sleep()是一個靜態方法。這意味着只對當前線程有效,一個常見的錯誤是調用p(),(這裏的t是一個不同於當前線程的線程)。即便是執行p(),也是當前線程進入睡眠,而不是t線程。end()是過時的方法,使用suspend()導致線程進入停滯狀態,該線程會一直持有對象的監視器,suspend()容易引起死鎖問題。

()使當前線程出於“不可運行”狀態,和sleep()不同的是wait是object的方法而不是thread。調用 ()時,線程先要獲取這個對象的對象鎖,當前線程必須在鎖對象保持同步,把當前線程添加到等待隊列中,隨後另一線程可以同步同一個對象鎖來調用fy(),這樣將喚醒原來等待中的線程,然後釋放該鎖。基本上wait()/notify()與sleep() /interrupt()類似,只是前者需要獲取對象鎖。

7、在靜態方法上使用同步時會發生什麼事?

同步靜態方法時會獲取該類的“Class”對象,所以當一個線程進入同步的靜態方法中時,線程監視器獲取類本身的對象鎖,其它線程不能進入這個類的任何靜態同步方法。它不像實例方法,因爲多個線程可以同時訪問不同實例同步實例方法。

8、當一個同步方法已經執行,線程能夠調用對象上的非同步實例方法嗎?

可以,一個非同步方法總是可以被調用而不會有任何問題。實際上,Java沒有爲非同步方法做任何檢查,鎖對象僅僅在同步方法或者同步代碼塊中檢查。如果一個方法沒有聲明爲同步,即使你在使用共享數據Java照樣會調用,而不會做檢查是否安全,所以在這種情況下要特別小心。一個方法是否聲明爲同步取決於臨界區訪問(critial section access),如果方法不訪問臨界區(共享資源或者數據結構)就沒必要聲明爲同步的。

下面有一個示例說明:Common類有兩個方法synchronizedMethod1()和method1(),MyThread類在獨立的線程中調用這兩個方法。

public class Common {

public synchronized void synchronizedMethod1() {

tln("synchronizedMethod1 called");

try {

p(1000);

} catch (InterruptedException e) {

tStackTrace();

}

tln("synchronizedMethod1 done");

}

public void method1() {

tln("Method 1 called");

try {

p(1000);

} catch (InterruptedException e) {

tStackTrace();

}

tln("Method 1 done");

}

}

public class MyThread extends Thread {

private int id = 0;

private Common common;

public MyThread(String name, int no, Common object) {

super(name);

common = object;

id = no;

}

public void run() {

tln("Running Thread" + ame());

try {

if (id == 0) {

hronizedMethod1();

} else {

od1();

}

} catch (Exception e) {

tStackTrace();

}

}

public static void main(String[] args) {

Common c = new Common();

MyThread t1 = new MyThread("MyThread-1", 0, c);

MyThread t2 = new MyThread("MyThread-2", 1, c);

t();

t();

}

}

這裏是程序的輸出: