31
32
33
public class Test {
# private int i = 10;
private Object object = new Object();
public static void main( Test();
MyThread thread1 = test.new MyThread();
MyThread thread # thread2.start(); } @Override public void run() { synchronized (ob # System.out.println("i:"+i); try { ## Thread.currentThread( ).sleep(10000);
} catch (InterruptedException e) {
}
(問題"+Thread.currentThread().getName()+"睡眠結束");
i++; ## ## }
卷
輸出結果:
從上面輸出結果可以看出,當Thread-0進入睡眠狀態之後,Thread-1並沒有去執行具體的任務。只有當Thread-0執行完之後,此時Thread-0釋放了物件鎖,Thread-1才開始執行。
注意,如果呼叫了sleep方法,必須捕獲InterruptedException異常或將該異常向上層拋出。當執行緒睡眠時間滿後,不一定會立即執行,因為此時CPU可能正在執行其他的任務。所以說呼叫sleep方法相當於讓執行緒進入阻塞狀態。
4)yield方法
呼叫yield方法會讓目前執行緒交出CPU權限,讓CPU去執行其他的執行緒。它跟sleep方法類似,同樣不會釋放鎖定。但是yield不能控制特定的交出CPU的時間,另外,yield方法只能讓擁有相同優先權的執行緒有取得CPU執行時間的機會。
注意,呼叫yield方法並不會讓執行緒進入阻塞狀態,而是讓執行緒重回就緒狀態,它只需要等待重新取得CPU執行時間,這一點是和sleep方法不一樣的。
5)join方法
join方法有三個重載版本:
###### #######1######2######3#############join()######join(long millis) //參數為毫秒######join(long millis,int nanoseconds) //第一參數為毫秒,第二個參數為奈秒###############
假如在main執行緒中,呼叫thread.join方法,則main方法會等待thread執行緒執行完畢或等待一定的時間。如果呼叫的是無參join方法,則等待thread執行完畢,如果呼叫的是指定了時間參數的join方法,則等待一定的事件。
看下面一個範例:
1
#2
3
4
5
6
7
8
9101112#13#14#15#16 17181920212223242526272829 |
30
public class Test { ##
public static void main(String[] args) throws IOException ("進入執行緒"+Thread.currentThread().getName());
Test test = new Test();
MyThread thread1 = test. MyThreadthread1 = test.Preadthread1 thread1.start();# try { p. # thread1.join();
@);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
#
class MyThread extends Thread{
@Override
ystem.out.println("進入線程"+Thread .currentThread().getName());
try {
} catch (InterruptedException e) {
// TODO: handle Thread.currentThread().getName()+"執行完畢");
}
}
}
|
###########################################################################################################
輸出結果:
可以看出,當呼叫thread1.join()方法後,main執行緒會進入等待,然後等待thread1執行完後再繼續執行。
其實呼叫join方法是呼叫了Object的wait方法,這個可以透過檢視原始碼得知:
# wait方法會讓執行緒進入阻塞狀態,並且會釋放執行緒佔有的鎖,並交出CPU執行權限。
由於wait方法會讓執行緒釋放物件鎖定,所以join方法同樣會讓執行緒釋放對一個物件所持有的鎖定。具體的wait方法使用在後面文章中給出。
6)interrupt方法
interrupt,顧名思義,即中斷的意思。單獨呼叫interrupt方法可以使得處於阻塞狀態的執行緒拋出一個異常,也就說,它可以用來中斷一個正處於阻塞狀態的執行緒;另外,透過interrupt方法和isInterrupted()方法來停止正在執行的執行緒。
以下看一個範例:
1
2345678
9
10
11
12
#13
#14
#15
#16
17
18
19
| 20
21
22
23
24
25
26
27
28
##public class Test { public static void main(String[] args) throws IOException { Test test = new Test(); MyThread thread = test. new MyThread(); thread.start(); try { } catch (InterruptedException e) { }##1
class MyThread extends Thread{
@Override
public voidrun() { # System.out.println("進入睡眠狀態") ; Thread.currentThread().sleep(10000); } catch (InterruptedException e) { System.out.println("取得中斷異常"); ("run方法執行完畢"); # }# } |
}
#######################
輸出結果:
#
從這裡可以看出,透過interrupt方法可以中斷處於阻塞狀態的執行緒。那麼能不能中斷處於非阻塞狀態的執行緒呢?看下面這個範例:
1 ##2#34#567##8
9
10111213#14#15#16# 17181920#21#22#23##24 |
25
public class Test { public static void main(String[] args) throws IO ## Test test = new Test();
MyThread thread = test.new MyThread();#
Thread.currentThread().sleep(2000); ## } c } thread.interrupt (); } # class MyThread extends Thread{ int i = = 0;
while(i< .println(i+" while迴圈");
i++;
}
}
}
}
執行程式會發現,while迴圈會一直運作直到變數i的值超出Integer.MAX_VALUE。所以說直接呼叫interrupt方法不能中斷正在執行中的執行緒。
但是如果配合isInterrupted()能夠中斷正在運行的線程,因為呼叫interrupt方法相當於將中斷標誌位置為true,那麼可以透過呼叫isInterrupted()判斷中斷標誌是否被置位來中斷線程的執行。例如下面這段程式碼:
1 ##2
1##2
#3
4
5
6
##10
11
12
13
14
15
16
| # #17
18
19
20
#21
#22
#23
# 24
25
public class Test {
public class Test {
public static void main(String[] args) throws IOException public static void main(String[] args) throws IOException public static void main(String[] args) throws IOException public static void main(String[] args) throws IOException public static void main(String[] args) throws IOException public static main(String[] ## Test test = new Test(); MyThread thread = test.new { Thread.currentThread().sleep(2000);## } c }
thread. interrupt();
}
class MyThread extends Thread{
@Override
public void run() {
int i = 0;
| while(!is1 System.out.println(i+" while迴圈"); i++; }#1
# 運作會發現,列印若干個值之後,while循環就停止列印了。 但是一般情況下不建議透過這種方式中斷線程,一般會在MyThread類別中增加一個屬性 isStop來標誌是否結束while循環,然後再在while循環中判斷isStop的值。
#1234567#89 ##10 11
12
13
| 14
class MyThread extends Thread{
private volatile # private volatile boolean isStop = false; @Override public void run() {# while(!isStop){
i++;
)# public void setStop(boolean stop){
this.isStop = stop;
}
# }
# 那麼就可以在外面透過呼叫setStop方法來終止while循環。
7)stop方法
stop方法已經是一個廢棄的方法,它是一個不安全的方法。因為調用stop方法會直接終止run方法的調用,並且會拋出一個ThreadDeath錯誤,如果線程持有某個物件鎖的話,會完全釋放鎖,導致物件狀態不一致。所以stop方法基本上是不會被用到的。
8)destroy方法
destroy方法也是廢棄的方法。基本不會被使用。
以下是幾個關係到執行緒屬性:
1)getId
用來得到執行緒ID
2)getName和setName
2)getName和setName # 用來得到或設定執行緒名稱。 3)getPriority和setPriority 用來取得和設定執行緒優先權。 4)setDaemon和isDaemon 用來設定線程是否成為守護線程和判斷線程是否是守護線程。 守護線程和使用者線程的區別在於:守護線程依賴創建它的線程,而使用者線程則不依賴。舉個 簡單的例子:如果在main線程中建立了一個守護線程,當main方法運行完畢之後,守護線程也會隨著消亡。而使用者執行緒則不會,使用者執行緒會一直運行直到其 運行完畢。在JVM中,像垃圾收集器線程就是守護線程。
Thread類別有一個比較常用的靜態方法currentThread()用來取得目前執行緒。 在上面已經說到了Thread類別中的大部分方法,那麼Thread類別中的方法呼叫到底會引起執行緒狀態發生怎樣的變化呢?下面一張圖就是在上面的圖表上改良而來的:
####### ###### ##### |
|
|