1. 程式人生 > >對於Java多線程的常見問題

對於Java多線程的常見問題

銷毀 .html blog exc pub 如果 wait方法 完成 共享變量

最近在準備工作面試的問題,所以找了很多的資料,和自己整理了相關可能會考到的。每天爭取發一篇。

1.多線程

實現方法:

一、繼承Thread,重寫run方法,調用start即可。

Class Thread1 extends Thread{

Public void run(){

//添加代碼

}

}

Public static void main(String[] args){

Thread1 st = new Thread1();

St.start();

}

二、實現runnable接口,重寫run方法,調用start。

Class RunThrad implements runnable{

Public void run(){

//添加代碼

}

}

RunThread t = new RunThread();

Thread th = new Thread(t);

th.start();

三、實現Callable接口類,並重寫call方法,使用FutureTask類來包裝Callable實現類的對象,並且使用FutureTask對象來作為Thread對象的target來創建線程。

class Mycallable implements Callable<Integer>{

Public int call(){

//添加代碼

}

}

public static void main(String[] args){

Mycallable<Integer> mycall = new Mycallable<Integer>();

FutureTask<Integer> ft = new FutureTask<Integer>(mycall);

Thread th = new Thread(ft);

th.start();

}

實現runnable和callable比繼承Thread方法的優勢:

1、避免單繼承的問題。

2、線程池只能夠放入runnable和callable類的線程。

線程主要有五種狀態,如下:

技術分享

接下來介紹sleep,wait,notify,notifyAll,join,yield六種方法

對於wait,notify,notifyAll這三個,屬於object類的方法,但必須搭配synchronized同步塊來使用,即在synchronized修飾的同步代碼塊中或者方法中調用wait或者notify/notifyAll:

由於wait,notify/notifyAll是放在同步代碼塊中的,所以線程在執行的時候,肯定是進入了臨界狀態的,即該線程肯定是獲得了鎖的。

當執行wait方法時,會把當前的鎖釋放掉,讓出cpu,進入等待狀態。

當執行notify/notifyAll方法時,喚醒一個等待該對象鎖的線程,然後繼續往下執行,直到執行完synchronized的代碼後,再將鎖釋放。(註意,notify/notifyAll執行後,並不立即釋放鎖,而是需要等待執行完synchronized的代碼後)

如果在線程A,線程B中,在線程A中,執行wait,在線程B中執行notify,如果線程B先執行了notify,然後就結束了,然後線程A才去執行wait,那麽此時線程A就無法被喚醒了。舉例如下:有3個線程A,B,C。

class T implements Runnable{

public String i;

public String index;

public T(String i,String index){

this.i = i;

this.index = index;

}

@Override

public void run() {

synchronized (index) {

while (true) {

try {

index.notifyAll();

System.out.println(i);

index.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

public class demo {

public static void main(String[] args){

String string1 = "s1";

String string2 = "s2";

String string3 = "s3";

String index = "test";

T a1 = new T(string1,index);

T a2 = new T(string2,index);

T a3 = new T(string3,index);

Thread thread1 = new Thread(a1);

Thread thread2 = new Thread(a2);

Thread thread3 = new Thread(a3);

thread1.start();

thread2.start();

thread3.start();

}

}

輸出結果:

s2

s1

s3

s1

s2

s1

s3

s1

……

多線程中測試某個條件的變化用 if 還是用 while?

以前一直不明白 當在線程的run()方法中需要測試某個條件時,為什麽用while,而不用if,直到看到了這個簡單的例子,終於明白了。。。。

這個例子是這樣的:

有兩個線程從List中刪除數據,而只有一個線程向List中添加數據。初始時,List為空,只有往List中添加了數據之後,才能刪除List中的數據。添加數據的線程向List添加完數據後,調用notifyAll(),喚醒了兩個刪除線程,但是它只添加了一個數據,而現在有兩個喚醒的刪除線程,這時怎麽辦??

如果用 if 測試List中的數據的個數,則會出現IndexOutofBoundException,越界異常。原因是,List中只有一個數據,第一個刪除線程把數據刪除後,第二個線程再去執行刪除操作時,刪除失敗,從而拋出 IndexOutofBoundException。

但是如果用while 測試List中數據的個數,則不會出現越界異常!!!神奇。

當wait等待的條件發生變化時,會造成程序的邏輯混亂---即,List中沒有數據了,再還是有線程去執行刪除數據的操作。因此,需要用while循環來判斷條件的變化,而不是用if。

兩個線程之間的通信,可以采用如下兩種方式,一種是基於while輪詢,另外一種就是wait/notify的方式。

基於while輪詢的,B線程一直 一直循環條件,當符合條件時,則拋出異常,結束線程。

基於wait/notify的方式,則使用共享變量。當A線程放棄CPU使用權,進入阻塞狀態,則B線程獲得共享變量,開始執行,執行完畢後,B線程結束,放棄CPU使用權,A線程繼續。容易出現的問題是,A線程尚未執行,B線程先執行,打亂執行順序。則邏輯錯誤。

參考案例在:http://www.cnblogs.com/hapjin/p/5492619.html

sleep:

sleep讓當前線程休眠指定的時間。休眠完成後,狀態轉到就緒狀態。

yield: yield是放棄當前CPU資源,將CPU資源讓給其他線程去使用,但放棄的時間不確定。

join:

大部分情況下,主線程啟動了子線程,如果子線程需要完成大量復雜的運算,則主線程會先於子線程結束。但主線程如果需要在子線程運行完畢後使用子線程的結果,則必須在主線程中使用join,這樣主線程會等待子線程結束,然後主線程再結束。

方法join,是使得所屬線程對象x正常執行完run方法,而使當前線程z進行無限制阻塞,直到對象x結束後,再繼續執行z後面的代碼。

public class demo

{

public static void main(String[] args) throws InterruptedException

{

Thread producer = new Producer();

producer.start();

producer.join();

System.out.println("main end");

}

}

class Producer extends Thread

{

public void run()

{

for (int i = 0; i < 100000; i++)

System.out.println("producer end");

}

}

在以上案例中,當把producer.join()註釋掉後,會先打印main end,再打印producer end。因為子線程運算復雜,所以主線程會先結束。而如果加上這一句,則主線程會等待producer線程的結束,主線程再銷毀。也就是說,哪一個線程被調用,則必須等待該線程結束,調用的主線程才能繼續執行下一步。

對於Java多線程的常見問題