在學(xué)校的論壇Java版發(fā)現(xiàn)很多問關(guān)于這樣的問題,比如這幾個方法有什么區(qū)別,想看t.interrupt()方法后線程的中斷狀態(tài);如何終止一個線程
其實之前已經(jīng)大部分提及到。現(xiàn)總結(jié)一下,然后加上例子,畢竟例子容易理解
http://www.tkk7.com/fhtdy2004/archive/2009/06/08/280728.html中有關(guān)interrupt()的解釋已經(jīng)很清楚了
interrupt
public void interrupt()
- 中斷線程。
如果當(dāng)前線程沒有中斷它自己(這在任何情況下都是允許的),則該線程的 checkAccess
方法就會被調(diào)用,這可能拋出 SecurityException
。
如果線程在調(diào)用 Object
類的 wait()
、wait(long)
或 wait(long, int)
方法,或者該類的 join()
、join(long)
、join(long, int)
、sleep(long)
或 sleep(long, int)
方法過程中受阻,則其中斷狀態(tài)將被清除,它還將收到一個 InterruptedException
。
如果該線程在
可中斷的通道
上的 I/O 操作中受阻,則該通道將被關(guān)閉,該線程的中斷狀態(tài)將被設(shè)置并且該線程將收到一個 ClosedByInterruptException
。
如果該線程在一個 Selector
中受阻,則該線程的中斷狀態(tài)將被設(shè)置,它將立即從選擇操作返回,并可能帶有一個非零值,就好像調(diào)用了選擇器的 wakeup
方法一樣。
如果以前的條件都沒有保存,則該線程的中斷狀態(tài)將被設(shè)置。
-
-
- 拋出:
SecurityException
- 如果當(dāng)前線程無法修改該線程
interrupted
public static boolean interrupted()
- 測試當(dāng)前線程是否已經(jīng)中斷。線程的中斷狀態(tài) 由該方法清除。換句話說,如果連續(xù)兩次調(diào)用該方法,則第二次調(diào)用將返回 false(在第一次調(diào)用已清除了其中斷狀態(tài)之后,且第二次調(diào)用檢驗完中斷狀態(tài)前,當(dāng)前線程再次中斷的情況除外)。
-
-
- 返回:
- 如果當(dāng)前線程已經(jīng)中斷,則返回
true
;否則返回 false
。
- 另請參見:
isInterrupted()
isInterrupted
public boolean isInterrupted()
- 測試線程是否已經(jīng)中斷。線程的中斷狀態(tài) 不受該方法的影響。
-
-
- 返回:
- 如果該線程已經(jīng)中斷,則返回
true
;否則返回 false
。
- 另請參見:
interrupted()
t.interrupt()不會中斷正在執(zhí)行的線程,只是將線程的標(biāo)志位設(shè)置成true。但是如果線程在調(diào)用sleep(),join(),wait()方法時線程被中斷,則這些方法會拋出InterruptedException,在catch塊中捕獲到這個異常時,線程的中斷標(biāo)志位已經(jīng)被設(shè)置成false了,因此在此catch塊中調(diào)用t.isInterrupted(),Thread.interrupted()始終都為false,
而t.isInterrupted與Thread.interrupted()的區(qū)別是API中已經(jīng)說明很明顯了,Thread.interrupted()假如當(dāng)前的中斷標(biāo)志為true,則調(diào)完后會將中斷標(biāo)志位設(shè)置成false
package threadtest;

import java.util.Timer;
import java.util.TimerTask;


class CanStop extends Thread
{

private int counter = 0;


public void run()
{
boolean done = false;

try
{
Thread.sleep(100);//設(shè)置成100比主線程中的500要小

}catch(InterruptedException ie)
{
ie.printStackTrace();
//return;假如要使用interrupt來終止線程則在捕獲的InterruptedException中return
}

while (counter < 100000 &&!done)
{
System.out.println(counter++);
//在主線程中調(diào)用stoppable.interrupt()之前為false,假如之后沒有調(diào)用Thread.interrupted()則一直為true,
//否則為第一次為true,調(diào)用Thread.interrupted之后為false
System.out.println("in thread stoppable.isInterrupted() "+isInterrupted());
//System.out.println("stoppable.isInterrupted() "+Thread.interrupted());////在主線程中調(diào)用stoppable.interrupt()之前為false,之后只有第一個會顯示為true,之后全為false
//調(diào)用Thread.interrupted()一次會清除線程的中斷標(biāo)志位,因此以后都為false

if(Thread.interrupted()==true)
{

try
{
//Thread.interrupted()會清除中斷標(biāo)志位,顯然這里面只會調(diào)用一次
System.out.println("in thread after Thread.interrupted() "+isInterrupted());
sleep(10000);

}catch(InterruptedException ie)
{
ie.printStackTrace();
}
}
}
}
}


public class CheckInterrupt
{

public static void main(String[] args)
{
final CanStop stoppable = new CanStop();
stoppable.start();

new Timer(true).schedule(new TimerTask()
{

public void run()
{
System.out.println("Requesting Interrupt");
stoppable.interrupt();//不會中斷正在執(zhí)行的線程,原因是因為interrupt()方法只設(shè)置中斷狀態(tài)標(biāo)志位為true
System.out.println("in timer stoppable.isInterrupted() "+stoppable.isInterrupted());
}
}, 500); // run() after 500 milliseconds
}
}


2,關(guān)于interrupte()打斷sleep()
package threadtest;

//Understanding join().


class Sleeper extends Thread
{
private int duration;


public Sleeper(String name, int sleepTime)
{
super(name);
duration = sleepTime;
start();
}


public void run()
{

try
{
sleep(duration);

} catch (InterruptedException e)
{
// System.out.println(getName() + " was interrupted. " +
// "isInterrupted(): " + isInterrupted());
System.out.println(getName() + " in catch Thread.interrupted(). "
+ "Thread.interrupted(): " + Thread.interrupted());
return;
}
System.out.println(getName() + " has awakened");
}
}


class Joiner extends Thread
{
private Sleeper sleeper;


public Joiner(String name, Sleeper sleeper)
{
super(name);
this.sleeper = sleeper;
start();
}


public void run()
{

try
{
sleeper.join();

} catch (InterruptedException e)
{
//run方法不能Throw CheckedException,要拋只能拋出RuntimeException,也不會被主線程捕獲
//要使主線程能夠捕獲這個RuntimeException請參見另外一篇文章
//地址:http://www.tkk7.com/fhtdy2004/archive/2009/08/07/290210.html
throw new RuntimeException(e);
}
System.out.println(getName() + " join completed");
}
}


public class Joining
{


public static void main(String[] args)
{
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc",grumpy);
grumpy.interrupt();
//doc.interrupt();

}
}

Sleeper是一個會睡上一段時間的Thread,至于睡多長時間,這要由構(gòu)造函數(shù)的參數(shù)決定。Sleeper的run( )的sleep( )可以因時限到期而返回,也可以被interrupt( )打斷。catch語句在報告中斷的同時,會一并報告isInterrupted( )。當(dāng)有別的線程調(diào)用了本線程的interrupt( )時,會設(shè)置一個標(biāo)記以表示這個這個線程被打斷了。當(dāng)本線程捕獲這個異常的時候,會清除這個標(biāo)志。所以catch語句會永遠(yuǎn)報告說isInterrupted( )是false。這個標(biāo)記是用來應(yīng)付其它情況的,或許在沒出異常的情況下,線程要用它來檢查自己是不是被中斷了。
Joiner是另一個線程,它調(diào)用了Sleeper的join( ),所以它要等Sleeper醒過來。main( )創(chuàng)建了兩個Sleeper分派給兩個Joiner。你會發(fā)現(xiàn),不論Sleeper是被打斷還是正常結(jié)束,Joiner都會隨Sleeper一道結(jié)束。
2,如何終止一個線程:
package test.thread.one;

import java.util.Timer;
import java.util.TimerTask;


class CanStop extends Thread
{
// Must be volatile:
private volatile boolean stop = false;

private int counter = 0;


public void run()
{

while (!stop && counter < 100000)
{
System.out.println(counter++);
}
if (stop)
System.out.println("Detected stop");
}


public void requestStop()
{
stop = true;
}
}


public class Stopping
{

public static void main(String[] args)
{
final CanStop stoppable = new CanStop();
stoppable.start();

new Timer(true).schedule(new TimerTask()
{

public void run()
{
System.out.println("Requesting stop");
stoppable.requestStop();
}
}, 500); // run() after 500 milliseconds
}
}

stop必須是
volatile的,這樣才能確保
run( )方法能看到它(否則它會使用本地的緩存值)。這個線程的"任務(wù)"是打印10,000個數(shù)字,所以當(dāng)
counter >= 10000或有人要它停下來的時候,它就結(jié)束了。注意
requestStop( )不是
synchronized,因為
stop既是
boolean(改成
true是一個原子操作)又是
volatile的。
或者
package test.thread.three;

import java.util.Timer;
import java.util.TimerTask;


class CanStop extends Thread
{
private boolean stop = false;

private int counter = 0;


public void run()
{
boolean done = false;

try
{
Thread.sleep(100);

}catch(InterruptedException ie)
{
ie.printStackTrace();
//return;假如要使用interrupt來終止線程則在捕獲的InterruptedException中return
}

while (!getStopRequest() && counter < 100000 &&!done)
{
System.out.println(counter++);
}
if (getStopRequest())
System.out.println("Detected stop");
}

public synchronized boolean getStopRequest()
{
return stop;
}


public synchronized void requestStop()
{
stop = true;
}
}


public class Stopping
{

public static void main(String[] args)
{
final CanStop stoppable = new CanStop();
stoppable.start();

new Timer(true).schedule(new TimerTask()
{

public void run()
{
System.out.println("Requesting stop");
stoppable.requestStop();
}
}, 500); // run() after 500 milliseconds
}
}

打斷受阻的線程
有時線程受阻之后就不能再做輪詢了,比如在等輸入,這時你就不能像前面那樣去查詢旗標(biāo)了。碰到這種情況,你可以用Thread.interrupt( )方法打斷受阻的線程:

//: c13:Interrupt.java
// Using interrupt() to break out of a blocked thread.
import java.util.*;

class Blocked extends Thread
{

public Blocked()
{
System.out.println("Starting Blocked");
start();
}

public void run()
{

try
{

synchronized(this)
{
wait(); // Blocks
}

} catch(InterruptedException e)
{
System.out.println("Interrupted");
}
System.out.println("Exiting run()");
}
}

public class Interrupt
{
static Blocked blocked = new Blocked();

public static void main(String[] args)
{

new Timer(true).schedule(new TimerTask()
{

public void run()
{
System.out.println("Preparing to interrupt");
blocked.interrupt();
blocked = null; // to release it
}
}, 2000); // run() after 2000 milliseconds
}
} ///

3.避免過多的同步,永遠(yuǎn)不要在循環(huán)外面調(diào)用wait
為了避免死鎖的危險,在一個被同步的的方法或者代碼快中,永遠(yuǎn)不要放棄對客戶的限制。
換句話說,在一個被同步的區(qū)域內(nèi)部,不要調(diào)用一個可被改寫的公有或受保護(hù)的方法(這樣的方法往往是一個抽象方法,但偶爾他們也會有一個默認(rèn)的實現(xiàn),)從包含該同步區(qū)域的類的角度來看,這樣的方法是一個外來者alien。這個類不知道該類會做什么事情,也控制不力它。客戶可以為這個外來方法提供一個實現(xiàn),并且在該方法中創(chuàng)建了一個線程,再回調(diào)到這個類中。然后,新建的線程試圖獲取原線程所擁有的那把鎖,這樣會導(dǎo)致新建的線程被阻塞。如果創(chuàng)建該線程的方法在等待這個線程完成這個任務(wù),則死鎖就形成了。
Object.wait方法的作用是使一個線程等待某個條件。它一定是在一個同步區(qū)域中被調(diào)用,而且該同步區(qū)域鎖住了被調(diào)用的對象。下面是wait方法的標(biāo)準(zhǔn)模式:
synchronized(obj){
while(<condition does not hold>)
obj.wait();
...//perform action appropriate to condition
}
總是使用wait循環(huán)模式來調(diào)用wait方法。而不是if來調(diào)用。永遠(yuǎn)不要在循環(huán)的外面調(diào)用wait。循環(huán)被用于等待的前后測試條件
package effective.java;

import java.io.BufferedInputStream;
import java.util.LinkedList;
import java.util.List;


public abstract class WorkQueue
{
private final List queue = new LinkedList();
private boolean stopped = false;
StringBuffer sb;
BufferedInputStream bis;

protected WorkQueue()
{
new WorkerThread2().start();
}

public final void enqueue(Object workItem)
{

synchronized(queue)
{
queue.add(workItem);
queue.notify();
}
}

public final void stop()
{

synchronized(queue)
{
stopped = true;
queue.notify();
}
}
protected abstract void processItem(Object workItem)throws InterruptedException;
//Broken - invokes alien method from synchronized block

private class WorkerThread extends Thread
{

public void run()
{

while(true)
{

synchronized(WorkQueue.this.queue)
{

try
{

while(queue.isEmpty() && !stopped)
{
queue.wait();
}

}catch(InterruptedException ie)
{
ie.printStackTrace();
return;
}
if(stopped)
return;
Object workItem = queue.remove(0);

try
{
processItem(workItem);//lock held

}catch(InterruptedException ie)
{
System.out.println("ddd"+ie);
return;
}
}
}
}
}
//Alien method outside synchronized block -"open call"

private class WorkerThread2 extends Thread
{

public void run()
{

while(true)
{
Object workItem = null;

synchronized(WorkQueue.this.queue)
{

try
{

while(queue.isEmpty() && !stopped)
{
queue.wait();
}

}catch(InterruptedException ie)
{
return;
}
if(stopped)
return;
workItem = queue.remove(0);
}

try
{
processItem(workItem);//No lock held

}catch(InterruptedException ie)
{
return;
}
}
}
}
}

package effective.java;


public class DisplayQueue extends WorkQueue
{

@Override

protected void processItem(Object workItem) throws InterruptedException
{
System.out.println(workItem);
System.out.println("模擬此線程做耗時工作");
Thread.sleep(1000);
}

public static void main(String[] args)
{
WorkQueue wq = new DisplayQueue();

for(int i=0;i<10;i++)
{
String s = new String("object_"+i);
System.out.println("main thread add " + s+" to queue");
wq.enqueue(s);

try
{
Thread.sleep(500);

}catch(InterruptedException ie)
{
ie.printStackTrace();
}
}
//wq.stop();
}

}




class DeadLockQueue extends WorkQueue
{

@Override

protected void processItem(final Object workItem) throws InterruptedException
{

Thread child = new Thread()
{

public void run()
{
//DeadLockQueue.this.enqueue(workItem);
System.out.println("在將對象入隊列 "+workItem);
enqueue(workItem);
}
};
child.start();
child.join();//dead lock
}
}

4.保持可運行線程數(shù)量盡可能的少的主要技術(shù)是,讓每個線程做少量的工作,然后使用Object.wait等待某個條件發(fā)生,或者使用Thread.sleep()睡眠一段時間,
線程不應(yīng)該忙-等busy-wait,即反復(fù)的檢查一個數(shù)據(jù)結(jié)構(gòu),以等待某些事件發(fā)生。除了使程序易受調(diào)度器的變化的影響外,忙等這種做法還會增加處理器的負(fù)擔(dān)
busy-wait
package effective.java;

import java.util.LinkedList;
import java.util.List;


public abstract class WorkQueueBusyWait
{
private final List queue = new LinkedList();
private boolean stopped = false;

protected WorkQueueBusyWait()
{
new WorkThread().start();
}

public final void enqueue(Object workItem)
{

synchronized(queue)
{
queue.add(workItem);
}
}

public final void stop()
{

synchronized(queue)
{
stopped = true;
}
}
protected abstract void processItem(Object workitem) throws InterruptedException;

private class WorkThread extends Thread
{

public void run()
{
final Object QUEUE_IS_EMPTY = new Object();

while(true)
{
Object workItem = QUEUE_IS_EMPTY;

synchronized(queue)
{
if(stopped)
return;
if(!queue.isEmpty())
workItem = queue.remove(0);
}

if(workItem != QUEUE_IS_EMPTY)
{

try
{
processItem(workItem);

}catch(InterruptedException ie)
{
ie.printStackTrace();
return;
}
}
}
}
}
}


class PingPongQueue extends WorkQueue
{
volatile int count=0;
@Override

protected void processItem(final Object workItem) throws InterruptedException
{
count++;
WorkQueue recipient = (WorkQueue)workItem;
recipient.enqueue(this);
}
}

package effective.java;


public class WaitQueuePerf
{


/** *//**
* @param args
*/

public static void main(String[] args)
{
PingPongQueue q1 = new PingPongQueue();
PingPongQueue q2 = new PingPongQueue();
q1.enqueue(q2);

try
{
Thread.sleep(1000);

}catch(InterruptedException ie)
{
ie.printStackTrace();
}
int count = q1.count;

try
{
Thread.sleep(1000);

}catch(InterruptedException ie)
{
ie.printStackTrace();
}
System.out.println(q1.count-count);
q1.stop();
q2.stop();

}

}

posted on 2009-08-22 11:07
Frank_Fang 閱讀(4828)
評論(0) 編輯 收藏 所屬分類:
Java編程