原文地址:http://www.blogjava.net/fhtdy2004/archive/2009/08/22/292181.html
在学校的论坛Java版发现很多问关于这样的问题,比如这几个方法有什么区别,想看t.interrupt()方法后线程的中断状态;如何终止一个线程 其实之前已经大部分提及到。现总结一下,然后加上例子,毕竟例子容易理解http://www.blogjava.net/fhtdy2004/archive/2009/06/08/280728.html 中有关interrupt()的解释已经很清楚了
interrupt
public void interrupt ()
中断线程。
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess
方法就会被调用,这可能抛出 SecurityException
。
如果线程在调用 Object
类的 wait()
、wait(long)
或 wait(long, int)
方法,或者该类的 join()
、join(long)
、join(long, int)
、sleep(long)
或 sleep(long, int)
方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException
。
如果该线程在可中断的通道 上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException
。
如果该线程在一个 Selector
中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup
方法一样。
如果以前的条件都没有保存,则该线程的中断状态将被设置。
抛出:
SecurityException
- 如果当前线程无法修改该线程
interrupted
public static boolean interrupted ()
测试当前线程是否已经中断。线程的
中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
返回:
如果当前线程已经中断,则返回
true
;否则返回
false
。
另请参见:
isInterrupted()
isInterrupted
public boolean isInterrupted ()
测试线程是否已经中断。线程的
中断状态 不受该方法的影响。
返回:
如果该线程已经中断,则返回
true
;否则返回
false
。
另请参见:
interrupted()
t.interrupt()不会中断正在执行的线程,只是将线程的标志位设置成true。但是如果线程在调用sleep(),join(),wait()方法时线程被中断,则这些方法会抛出InterruptedException,在catch块中捕获到这个异常时,线程的中断标志位已经被设置成false了,因此在此catch块中调用t.isInterrupted(),Thread.interrupted()始终都为false, 而t.isInterrupted与Thread.interrupted()的区别是API中已经说明很明显了,Thread.interrupted()假如当前的中断标志为true,则调完后会将中断标志位设置成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 ); // 设置成100比主线程中的500要小 } catch (InterruptedException ie) { ie.printStackTrace(); // return;假如要使用interrupt来终止线程则在捕获的InterruptedException中return } while (counter < 100000 &&! done) { System.out.println(counter ++ ); // 在主线程中调用stoppable.interrupt()之前为false,假如之后没有调用Thread.interrupted()则一直为true, // 否则为第一次为true,调用Thread.interrupted之后为false System.out.println( " in thread stoppable.isInterrupted() " + isInterrupted()); // System.out.println("stoppable.isInterrupted() "+Thread.interrupted()); 在主线程中调用stoppable.interrupt()之前为false,之后只有第一个会显示为true,之后全为false // 调用Thread.interrupted()一次会清除线程的中断标志位,因此以后都为false if (Thread.interrupted() == true ) { try { // Thread.interrupted()会清除中断标志位,显然这里面只会调用一次 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(); // 不会中断正在执行的线程,原因是因为interrupt()方法只设置中断状态标志位为true System.out.println( " in timer stoppable.isInterrupted() " + stoppable.isInterrupted()); } }, 500 ); // run() after 500 milliseconds } }
2,关于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.blogjava.net/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 ,至于睡多长时间,这要由构造函数的参数决定。Sleeper 的run( ) 的sleep( ) 可以因时限到期而返回,也可以被interrupt( ) 打断。catch 语句在报告中断的同时,会一并报告isInterrupted( ) 。当有别的线程调用了本线程的interrupt( ) 时,会设置一个标记以表示这个这个线程被打断了。当本线程捕获这个异常的时候,会清除这个标志。所以catch 语句会永远报告说isInterrupted( ) 是false。这个标记是用来应付其它情况的,或许在没出异常的情况下,线程要用它来检查自己是不是被中断了。 Joiner 是另一个线程,它调用了Sleeper 的join( ) ,所以它要等Sleeper 醒过来。main( ) 创建了两个Sleeper 分派给两个Joiner 。你会发现,不论Sleeper 是被打断还是正常结束,Joiner 都会随Sleeper 一道结束。
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( ) 方法能看到它(否则它会使用本地的缓存值)。这个线程的"任务"是打印10,000个数字,所以当counter >= 10000 或有人要它停下来的时候,它就结束了。注意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 } }
打断受阻的线程 有时线程受阻之后就不能再做轮询了,比如在等输入,这时你就不能像前面那样去查询旗标了。碰到这种情况,你可以用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.避免过多的同步,永远不要在循环外面调用wait
为了避免死锁的危险,在一个被同步的的方法或者代码快中,永远不要放弃对客户的限制。 换句话说,在一个被同步的区域内部,不要调用一个可被改写的公有或受保护的方法(这样的方法往往是一个抽象方法,但偶尔他们也会有一个默认的实现,)从包含该同步区域的类的角度来看,这样的方法是一个外来者alien。这个类不知道该类会做什么事情,也控制不力它。客户可以为这个外来方法提供一个实现,并且在该方法中创建了一个线程,再回调到这个类中。然后,新建的线程试图获取原线程所拥有的那把锁,这样会导致新建的线程被阻塞。如果创建该线程的方法在等待这个线程完成这个任务,则死锁就形成了。
Object.wait方法的作用是使一个线程等待某个条件。它一定是在一个同步区域中被调用,而且该同步区域锁住了被调用的对象。下面是wait方法的标准模式: synchronized(obj){ while(<condition does not hold>) obj.wait(); ...//perform action appropriate to condition } 总是使用wait循环模式来调用wait方法。而不是if来调用。永远不要在循环的外面调用wait。循环被用于等待的前后测试条件
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.保持可运行线程数量尽可能的少的主要技术是,让每个线程做少量的工作,然后使用Object.wait等待某个条件发生,或者使用Thread.sleep()睡眠一段时间,线程不应该忙-等busy-wait,即反复的检查一个数据结构,以等待某些事件发生。 除了使程序易受调度器的变化的影响外,忙等这种做法还会增加处理器的负担 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(); } }