在学校的论坛Java版发现很多问关于这样的问题,比如这几个方法有什么区别,想看t.interrupt()方法后线程的中断状态;如何终止一个线程
其实之前已经大部分提及到。现总结一下,然后加上例子,毕竟例子容易理解
http://www.blogjava.net/fhtdy2004/archive/2009/06/08/280728.html中有关interrupt()的解释已经很清楚了
interruptpublic 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 - 如果当前线程无法修改该线程
--------------------------------------------------------------------------------
interruptedpublic static boolean interrupted()
测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
返回:
如果当前线程已经中断,则返回 true;否则返回 false。
另请参见:
isInterrupted()
--------------------------------------------------------------------------------
isInterruptedpublic 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
1. package threadtest;
2.
3. import java.util.Timer;
4. import java.util.TimerTask;
5.
6. class CanStop extends Thread {
7.
8. private int counter = 0;
9.
10. public void run() {
11. boolean done = false;
12. try{
13. Thread.sleep(100);//设置成100比主线程中的500要小
14. }catch(InterruptedException ie){
15. ie.printStackTrace();
16. //return;假如要使用interrupt来终止线程则在捕获的InterruptedException中return
17. }
18. while (counter < 100000 &&!done) {
19. System.out.println(counter++);
20. //在主线程中调用stoppable.interrupt()之前为false,假如之后没有调用Thread.interrupted()则一直为true,
21. //否则为第一次为true,调用Thread.interrupted之后为false
22. System.out.println("in thread stoppable.isInterrupted() "+isInterrupted());
23.
24. //System.out.println("stoppable.isInterrupted() "+Thread.interrupted()); 在主线程中调用stoppable.interrupt()之前为false,之后只有第一个会显示为true,之后全为false
25.
26. //调用Thread.interrupted()一次会清除线程的中断标志位,因此以后都为false
27. if(Thread.interrupted()==true){
28. try{
29. //Thread.interrupted()会清除中断标志位,显然这里面只会调用一次
30. System.out.println("in thread after Thread.interrupted() "+isInterrupted());
31. sleep(10000);
32. }catch(InterruptedException ie){
33. ie.printStackTrace();
34.
35. }
36. }
37. }
38. }
39.
40. }
41.
42. public class CheckInterrupt {
43. public static void main(String[] args) {
44. final CanStop stoppable = new CanStop();
45. stoppable.start();
46. new Timer(true).schedule(new TimerTask() {
47. public void run() {
48. System.out.println("Requesting Interrupt");
49. stoppable.interrupt();//不会中断正在执行的线程,原因是因为interrupt()方法只设置中断状态标志位为true
50. System.out.println("in timer stoppable.isInterrupted() "+stoppable.isInterrupted());
51. }
52. }, 500); // run() after 500 milliseconds
53. }
54. }
55.
56.
57. 2,关于interrupte()打断sleep()
58. package threadtest;
59.
60. //Understanding join().
61.
62. class Sleeper extends Thread {
63. private int duration;
64.
65. public Sleeper(String name, int sleepTime) {
66. super(name);
67. duration = sleepTime;
68. start();
69. }
70.
71. public void run() {
72. try {
73. sleep(duration);
74. } catch (InterruptedException e) {
75. // System.out.println(getName() + " was interrupted. " +
76. // "isInterrupted(): " + isInterrupted());
77. System.out.println(getName() + " in catch Thread.interrupted(). "
78. + "Thread.interrupted(): " + Thread.interrupted());
79. return;
80. }
81. System.out.println(getName() + " has awakened");
82. }
83. }
84.
85. class Joiner extends Thread {
86. private Sleeper sleeper;
87.
88. public Joiner(String name, Sleeper sleeper) {
89. super(name);
90. this.sleeper = sleeper;
91. start();
92. }
93.
94. public void run() {
95. try {
96. sleeper.join();
97. } catch (InterruptedException e) {
98. //run方法不能Throw CheckedException,要抛只能抛出RuntimeException,也不会被主线程捕获
99. //要使主线程能够捕获这个RuntimeException请参见另外一篇文章
100. //地址:http://www.blogjava.net/fhtdy2004/archive/2009/08/07/290210.html
101. throw new RuntimeException(e);
102. }
103. System.out.println(getName() + " join completed");
104. }
105. }
106.
107. public class Joining {
108.
109. public static void main(String[] args) {
110. Sleeper sleepy = new Sleeper("Sleepy", 1500),
111. grumpy = new Sleeper("Grumpy", 1500);
112. Joiner dopey = new Joiner("Dopey", sleepy),
113. doc = new Joiner("Doc",grumpy);
114. grumpy.interrupt();
115. //doc.interrupt();
116.
117. }
118. }
119.
120. Sleeper是一个会睡上一段时间的Thread,至于睡多长时间,这要由构造函数的参数决定。Sleeper的run( )的sleep( )可以因时限到期而返回,也可以被interrupt( )打断。catch语句在报告中断的同时,会一并报告isInterrupted( )。当有别的线程调用了本线程的interrupt( )时,会设置一个标记以表示这个这个线程被打断了。当本线程捕获这个异常的时候,会清除这个标志。所以catch语句会永远报告说isInterrupted( )是false。这个标记是用来应付其它情况的,或许在没出异常的情况下,线程要用它来检查自己是不是被中断了。
121. Joiner是另一个线程,它调用了Sleeper的join( ),所以它要等Sleeper醒过来。main( )创建了两个Sleeper分派给两个Joiner。你会发现,不论Sleeper是被打断还是正常结束,Joiner都会随Sleeper一道结束。
122.
123.
124.
125.
126.
127. 2,如何终止一个线程:
128. package test.thread.one;
129.
130. import java.util.Timer;
131. import java.util.TimerTask;
132.
133. class CanStop extends Thread {
134. // Must be volatile:
135. private volatile boolean stop = false;
136.
137. private int counter = 0;
138.
139. public void run() {
140. while (!stop && counter < 100000) {
141. System.out.println(counter++);
142. }
143. if (stop)
144. System.out.println("Detected stop");
145. }
146.
147. public void requestStop() {
148. stop = true;
149. }
150. }
151.
152. public class Stopping {
153. public static void main(String[] args) {
154. final CanStop stoppable = new CanStop();
155. stoppable.start();
156. new Timer(true).schedule(new TimerTask() {
157. public void run() {
158. System.out.println("Requesting stop");
159. stoppable.requestStop();
160. }
161. }, 500); // run() after 500 milliseconds
162. }
163. }
stop必须是volatile的,这样才能确保run( )方法能看到它(否则它会使用本地的缓存值)。这个线程的"任务"是打印10,000个数字,所以当counter >= 10000或有人要它停下来的时候,它就结束了。注意requestStop( )不是synchronized,因为stop既是boolean(改成true是一个原子操作)又是volatile的。
1. package test.thread.three;
2.
3. import java.util.Timer;
4. import java.util.TimerTask;
5.
6. class CanStop extends Thread {
7.
8. private boolean stop = false;
9.
10. private int counter = 0;
11.
12. public void run() {
13. boolean done = false;
14. try{
15. Thread.sleep(100);
16. }catch(InterruptedException ie){
17. ie.printStackTrace();
18. //return;假如要使用interrupt来终止线程则在捕获的InterruptedException中return
19. }
20. while (!getStopRequest() && counter < 100000 &&!done) {
21. System.out.println(counter++);
22. }
23. if (getStopRequest())
24. System.out.println("Detected stop");
25. }
26.
27.
28. public synchronized boolean getStopRequest(){
29. return stop;
30. }
31.
32. public synchronized void requestStop() {
33. stop = true;
34. }
35. }
36.
37. public class Stopping {
38. public static void main(String[] args) {
39. final CanStop stoppable = new CanStop();
40. stoppable.start();
41. new Timer(true).schedule(new TimerTask() {
42. public void run() {
43. System.out.println("Requesting stop");
44. stoppable.requestStop();
45. }
46. }, 500); // run() after 500 milliseconds
47. }
48. }
49.
50. 打断受阻的线程
51. 有时线程受阻之后就不能再做轮询了,比如在等输入,这时你就不能像前面那样去查询旗标了。碰到这种情况,你可以用Thread.interrupt( )方法打断受阻的线程:
52.
53. //: c13:Interrupt.java
54. // Using interrupt() to break out of a blocked thread.
55. import java.util.*;
56. class Blocked extends Thread {
57. public Blocked() {
58. System.out.println("Starting Blocked");
59. start();
60. }
61. public void run() {
62. try {
63. synchronized(this) {
64. wait(); // Blocks
65. }
66. } catch(InterruptedException e) {
67. System.out.println("Interrupted");
68. }
69. System.out.println("Exiting run()");
70. }
71. }
72. public class Interrupt {
73. static Blocked blocked = new Blocked();
74. public static void main(String[] args) {
75. new Timer(true).schedule(new TimerTask() {
76. public void run() {
77. System.out.println("Preparing to interrupt");
78. blocked.interrupt();
79. blocked = null; // to release it
80. }
81. }, 2000); // run() after 2000 milliseconds
82. }
83. } ///
3.避免过多的同步,永远不要在循环外面调用wait
为了避免死锁的危险,在一个被同步的的方法或者代码快中,永远不要放弃对客户的限制。
换句话说,在一个被同步的区域内部,不要调用一个可被改写的公有或受保护的方法(这样的方法往往是一个抽象方法,但偶尔他们也会有一个默认的实 现,)从包含该同步区域的类的角度来看,这样的方法是一个外来者alien。这个类不知道该类会做什么事情,也控制不力它。客户可以为这个外来方法提供一 个实现,并且在该方法中创建了一个线程,再回调到这个类中。然后,新建的线程试图获取原线程所拥有的那把锁,这样会导致新建的线程被阻塞。如果创建该线程 的方法在等待这个线程完成这个任务,则死锁就形成了。
Object.wait方法的作用是使一个线程等待某个条件。它一定是在一个同步区域中被调用,而且该同步区域锁住了被调用的对象。下面是wait方法的标准模式:
-
总是使用wait循环模式来调用wait方法。而不是if来调用。永远不要在循环的外面调用wait。循环被用于等待的前后测试条件1. synchronized(obj){ 2. while(<condition does not hold>) 3. obj.wait(); 4. ...//perform action appropriate to condition 5. }
1. package effective.java;
2.
3. import java.io.BufferedInputStream;
4. import java.util.LinkedList;
5. import java.util.List;
6.
7. public abstract class WorkQueue {
8.
9. private final List queue = new LinkedList();
10.
11. private boolean stopped = false;
12.
13. StringBuffer sb;
14. BufferedInputStream bis;
15.
16. protected WorkQueue(){
17. new WorkerThread2().start();
18. }
19.
20. public final void enqueue(Object workItem){
21. synchronized(queue){
22. queue.add(workItem);
23. queue.notify();
24. }
25. }
26.
27. public final void stop(){
28. synchronized(queue){
29. stopped = true;
30. queue.notify();
31. }
32. }
33.
34. protected abstract void processItem(Object workItem)throws InterruptedException;
35.
36. //Broken - invokes alien method from synchronized block
37. private class WorkerThread extends Thread{
38. public void run(){
39. while(true){
40. synchronized(WorkQueue.this.queue){
41. try{
42. while(queue.isEmpty() && !stopped){
43. queue.wait();
44. }
45. }catch(InterruptedException ie){
46. ie.printStackTrace();
47. return;
48. }
49.
50. if(stopped)
51. return;
52. Object workItem = queue.remove(0);
53. try{
54. processItem(workItem);//lock held
55. }catch(InterruptedException ie){
56. System.out.println("ddd"+ie);
57. return;
58. }
59. }
60. }
61. }
62. }
63.
64.
65. //Alien method outside synchronized block -"open call"
66. private class WorkerThread2 extends Thread{
67. public void run(){
68. while(true){
69. Object workItem = null;
70. synchronized(WorkQueue.this.queue){
71. try{
72. while(queue.isEmpty() && !stopped){
73. queue.wait();
74. }
75. }catch(InterruptedException ie){
76. return;
77. }
78.
79. if(stopped)
80. return;
81. workItem = queue.remove(0);
82. }
83.
84. try{
85. processItem(workItem);//No lock held
86. }catch(InterruptedException ie){
87. return;
88. }
89. }
90. }
91. }
92. }
93.
94. package effective.java;
95.
96. public class DisplayQueue extends WorkQueue {
97.
98. @Override
99. protected void processItem(Object workItem) throws InterruptedException {
100. System.out.println(workItem);
101. System.out.println("模拟此线程做耗时工作");
102. Thread.sleep(1000);
103. }
104.
105. public static void main(String[] args){
106. WorkQueue wq = new DisplayQueue();
107. for(int i=0;i<10;i++){
108. String s = new String("object_"+i);
109. System.out.println("main thread add " + s+" to queue");
110. wq.enqueue(s);
111. try{
112. Thread.sleep(500);
113. }catch(InterruptedException ie){
114. ie.printStackTrace();
115. }
116. }
117. //wq.stop();
118. }
119.
120. }
121.
122.
123.
124. class DeadLockQueue extends WorkQueue{
125.
126. @Override
127. protected void processItem(final Object workItem) throws InterruptedException {
128.
129. Thread child = new Thread(){
130. public void run(){
131. //DeadLockQueue.this.enqueue(workItem);
132. System.out.println("在将对象入队列 "+workItem);
133. enqueue(workItem);
134. }
135. };
136. child.start();
137. child.join();//dead lock
138.
139. }
140.
141.
142. }
4.保持可运行线程数量尽可能的少的主要技术是,让每个线程做少量的工作,然后使用Object.wait等待某个条件发生,或者使用 Thread.sleep()睡眠一段时间,线程不应该忙-等busy-wait,即反复的检查一个数据结构,以等待某些事件发生。除了使程序易受调度器 的变化的影响外,忙等这种做法还会增加处理器的负担
busy-wait
1. package effective.java;
2.
3. import java.util.LinkedList;
4. import java.util.List;
5.
6. public abstract class WorkQueueBusyWait {
7.
8. private final List queue = new LinkedList();
9.
10. private boolean stopped = false;
11.
12. protected WorkQueueBusyWait(){
13. new WorkThread().start();
14. }
15.
16. public final void enqueue(Object workItem){
17. synchronized(queue){
18. queue.add(workItem);
19. }
20. }
21.
22. public final void stop(){
23. synchronized(queue){
24. stopped = true;
25. }
26. }
27.
28. protected abstract void processItem(Object workitem) throws InterruptedException;
29.
30. private class WorkThread extends Thread{
31. public void run(){
32. final Object QUEUE_IS_EMPTY = new Object();
33. while(true){
34. Object workItem = QUEUE_IS_EMPTY;
35. synchronized(queue){
36. if(stopped)
37. return;
38. if(!queue.isEmpty())
39. workItem = queue.remove(0);
40. }
41. if(workItem != QUEUE_IS_EMPTY){
42. try{
43. processItem(workItem);
44. }catch(InterruptedException ie){
45. ie.printStackTrace();
46. return;
47. }
48. }
49. }
50. }
51. }
52. }
53.
54. class PingPongQueue extends WorkQueue{
55. volatile int count=0;
56. @Override
57. protected void processItem(final Object workItem) throws InterruptedException {
58. count++;
59. WorkQueue recipient = (WorkQueue)workItem;
60. recipient.enqueue(this);
61. }
62.
63. }
64.
65. package effective.java;
66.
67. public class WaitQueuePerf {
68.
69. /** *//**
70. * @param args
71. */
72. public static void main(String[] args) {
73.
74. PingPongQueue q1 = new PingPongQueue();
75. PingPongQueue q2 = new PingPongQueue();
76. q1.enqueue(q2);
77.
78. try{
79. Thread.sleep(1000);
80. }catch(InterruptedException ie){
81. ie.printStackTrace();
82. }
83.
84. int count = q1.count;
85. try{
86. Thread.sleep(1000);
87. }catch(InterruptedException ie){
88. ie.printStackTrace();
89. }
90. System.out.println(q1.count-count);
91. q1.stop();
92. q2.stop();
93.
94. }
95.
96. }