一個正在運行的線程除了正常的時間片中斷之外,能否被其他線程控制?或者說其他線程能否讓指定線程放棄CPU或者提前結束運行?
除了線程同步機制之外,還有兩種方法:
(1) Thread.stop(), Thread.suspend(), Thread.resume() 和Runtime.runFinalizersOnExit() 這些終止線程運行的方法 。這些方法已經被廢棄,使用它們是極端不安全的。
(2) Thread.interrupt() 方法是很好的選擇。但是使用的時候我們必須好好理解一下它的用處。
- //無法中斷正在運行的線程代碼
- class TestRunnable implements Runnable{
- public void run(){
- while(true)
- {
- System.out.println( "Thread is running..." );
- long time = System.currentTimeMillis();//去系統時間的毫秒數
- while((System.currentTimeMillis()-time < 1000)) {
- //程序循環1秒鐘,不同於sleep(1000)會阻塞進程。
- }
- }
- }
- }
- public class ThreadDemo{
- public static void main(String[] args){
- Runnable r=new TestRunnable();
- Thread th1=new Thread(r);
- th1.start();
- th1.interrupt();
- }
- }
- /運行結果:一秒鐘打印一次Thread is running...。程序沒有終止的任何跡象
//無法中斷正在運行的線程代碼
class TestRunnable implements Runnable{
public void run(){
while(true)
{
System.out.println( "Thread is running..." );
long time = System.currentTimeMillis();//去系統時間的毫秒數
while((System.currentTimeMillis()-time < 1000)) {
//程序循環1秒鐘,不同於sleep(1000)會阻塞進程。
}
}
}
}
public class ThreadDemo{
public static void main(String[] args){
Runnable r=new TestRunnable();
Thread th1=new Thread(r);
th1.start();
th1.interrupt();
}
}
//運行結果:一秒鐘打印一次Thread is running...。程序沒有終止的任何跡象
上面的代碼說明interrupt()並沒有中斷一個正在運行的線程,或者說讓一個running中的線程放棄CPU。那麼interrupt到底中斷什麼。
首先我們看看interrupt究竟在幹什麼。
當我們調用th1.interrput()的時候,線程th1的中斷狀態(interrupted status) 會被置位。我們可以通過Thread.currentThread().isInterrupted() 來檢查這個布爾型的中斷狀態。
在Core Java中有這樣一句話:"沒有任何語言方面的需求要求一個被中斷的程序應該終止。中斷一個線程只是爲了引起該線程的注意,被中斷線程可以決定如何應對中斷 "。好好體會這句話的含義,看看下面的代碼:
- //Interrupted的經典使用代碼
- public void run(){
- try{
- ....
- while(!Thread.currentThread().isInterrupted()&& more work to do){
- // do more work;
- }
- }catch(InterruptedException e){
- // thread was interrupted during sleep or wait
- }
- finally{
- // cleanup, if required
- }
- }
//Interrupted的經典使用代碼
public void run(){
try{
....
while(!Thread.currentThread().isInterrupted()&& more work to do){
// do more work;
}
}catch(InterruptedException e){
// thread was interrupted during sleep or wait
}
finally{
// cleanup, if required
}
}
很顯然,在上面代碼中,while循環有一個決定因素就是需要不停的檢查自己的中斷狀態。當外部線程調用該線程的interrupt 時,使得中斷狀態置位。這是該線程將終止循環,不在執行循環中的do more work了。
這說明: interrupt中斷的是線程的某一部分業務邏輯,前提是線程需要檢查自己的中斷狀態(isInterrupted())。
但是當th1被阻塞的時候,比如被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞時。調用它的interrput()方法。可想而知,沒有佔用CPU運行的線程是不可能給自己的中斷狀態置位的。這就會產生一個InterruptedException異常。
- //中斷一個被阻塞的線程代碼
- class TestRunnable implements Runnable{
- public void run(){
- try{
- Thread.sleep(1000000); //這個線程將被阻塞1000秒
- }catch(InterruptedException e){
- e.printStackTrace();
- //do more work and return.
- }
- }
- }
- public class TestDemo2{
- public static void main(String[] args) {
- Runnable tr=new TestRunnable();
- Thread th1=new Thread(tr);
- th1.start(); //開始執行分線程
- while(true){
- th1.interrupt(); //中斷這個分線程
- }
- }
- }
- /*運行結果:
- java.lang.InterruptedException: sleep interrupted
- at java.lang.Thread.sleep(Native Method)
- at TestRunnable.run(TestDemo2.java:4)
- at java.lang.Thread.run(Unknown Source)*/
//中斷一個被阻塞的線程代碼
class TestRunnable implements Runnable{
public void run(){
try{
Thread.sleep(1000000); //這個線程將被阻塞1000秒
}catch(InterruptedException e){
e.printStackTrace();
//do more work and return.
}
}
}
public class TestDemo2{
public static void main(String[] args) {
Runnable tr=new TestRunnable();
Thread th1=new Thread(tr);
th1.start(); //開始執行分線程
while(true){
th1.interrupt(); //中斷這個分線程
}
}
}
/*運行結果:
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at TestRunnable.run(TestDemo2.java:4)
at java.lang.Thread.run(Unknown Source)*/
*
如果線程被阻塞,它便不能覈查共享變量,也就不能停止。這在許多情況下會發生,例如調用
*
Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,他們都可能永
*
久的阻塞線程。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使
*
用某種機制使得線程更早地退出被阻塞的狀態。很不幸運,不存在這樣一種機制對所有的情況
*
都適用,但是,根據情況不同卻可以使用特定的技術。使用Thread.interrupt()中斷線程正
*
如Example1中所描述的,Thread.interrupt()方法不會中斷一個正在運行的線程。這一方法
*
實際上完成的是,在線程受到阻塞時拋出一箇中斷信號,這樣線程就得以退出阻塞的狀態。更
*
確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那麼,
*
它將接收到一箇中斷異常(InterruptedException),從而提早地終結被阻塞狀態。