我们先来看一个例子,在 for 循环中判断线程是否中断,如果中断则后面代码不再运行:
2. 在沉睡中停止
上面这个例子是先开始了线程中的sleep,然后再用 interrupt() 停止。下面我们反过来,再看看:
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("已经是停止状态了!我要退出了!");
break;
}
System.out.println("i = " + (i +1));
}
System.out.println("我被输出,如果此代码是 for 又继续运行,线程并未停止!");
}
}
public class Test {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(1000);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
/*
运行结果:
...
i = 287846
i = 287847
已经是停止状态了!我要退出了!
我被输出,如果此代码是 for 又继续运行,线程并未停止!
end!
*/
}
从结果上看,for 循环中的 break 只是结束了循环。如果 for 下面还有语句,依然会继续执行。那么如何解决语句继续执行的问题?
1. 抛出异常
public class MyThread2 extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("已经是停止状态了!我要退出了!");
throw new InterruptedException();
}
System.out.println("i = " + (i + 1));
}
System.out.println("我在 for 下面");
} catch (InterruptedException e) {
System.out.println("进 MyThread.java 类 run 方法中的 catch 了!");
e.printStackTrace();
}
}
}
public class Test2 {
public static void main(String[] args) {
try {
MyThread2 thread = new MyThread2();
thread.start();
Thread.sleep(1000);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
/*
运行结果:
...
i = 304678
i = 304679
end!
已经是停止状态了!我要退出了!
进 MyThread.java 类 run 方法中的 catch 了!
java.lang.InterruptedException
at com.leo.JavaImprove.chapter1.exceptionStopThread.MyThread2.run(MyThread2.java:15)
*/
}
从结果中可以看出,使用 抛出异常的方法之后,for 循环后面的语句并没有被继续执行了。
2. 在沉睡中停止
public class MyThread3 extends Thread {
@Override
public void run() {
super.run();
try {
System.out.println("run begin");
Thread.sleep(20000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止!进入 catch!" + this.isInterrupted());
e.printStackTrace();
}
}
}
public class Test3 {
public static void main(String[] args) {
try {
MyThread3 thread = new MyThread3();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
/*
运行结果:
run begin
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.leo.JavaImprove.chapter1.exceptionStopThread.MyThread3.run(MyThread3.java:13)
end!
在沉睡中被停止!进入 catch!false
*/
}
如果在 sleep 状态下停止线程,会进入 catch 语句(相当于前面的 throw new InterruptedException),并且清楚停止状态值,使 isInterrupted = false。
上面这个例子是先开始了线程中的sleep,然后再用 interrupt() 停止。下面我们反过来,再看看:
public class MyThread4 extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 100000; i++) {
System.out.println("i = " + (i+1));
}
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("先停止,再遇到了sleep!进入 catch!" + this.isInterrupted());
e.printStackTrace();
}
}
}
public class Test4 {
public static void main(String[] args) {
MyThread4 thread = new MyThread4();
thread.start();
thread.interrupt();
System.out.println("end!");
}
/*
运行结果:
end!
i = 1
i = 2
...
i = 99999
i = 100000
run begin
先停止,再遇到了sleep!进入 catch!false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
*/
}
所以,线程在运行后,先用 interrupt() 停止后执行到 sleep() 也会抛出异常,停止线程。
3. 暴力停止 stop()
public class MyThread extends Thread {
private int i = 0;
@Override
public void run() {
try {
while (true) {
i++;
System.out.println("i = " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(8000);
thread.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
*/
}
可见 stop() 方法会立刻停止线程,同时会释放锁,可能会使数据不一致。调用 stop() 方法时会抛出 java.lang.ThreadDeath 异常,通常情况下,此异常不需要显示地捕捉。stop() 方法已经被作废,不建议使用。
public class MyThread2 extends Thread {
@Override
public void run() {
try {
stop();
} catch (ThreadDeath e) {
System.out.println("进入了 catch 方法!");
e.printStackTrace();
}
}
}
public class Test2 {
public static void main(String[] args) {
MyThread2 thread = new MyThread2();
thread.start();
}
/*
进入了 catch 方法!
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:836)
*/
}
下面我们看一个 stop() 释放锁的例子:
public class SynchronizedObject {
private String username = "a";
private String password = "aa";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public synchronized void printString(String username, String password) {
try {
this.username = username;
Thread.sleep(100000);
this.password = password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyThread3 extends Thread {
private SynchronizedObject object;
public MyThread3(SynchronizedObject object) {
super();
this.object = object;
}
@Override
public void run() {
object.printString("b", "bb");
}
}
public class Test3 {
public static void main(String[] args) {
try {
SynchronizedObject object = new SynchronizedObject(); //实例化 object,此时 username=a, password=aa
MyThread3 thread = new MyThread3(object);
thread.start(); //开始线程,执行 printString 方法
Thread.sleep(500); //挂起 main 线程,留时间给 thread.printString("b", "bb")执行,此时 this.username = "b"
thread.stop(); //停止线程 thread, 同时也释放了 线程中 printString()的方法锁。这个时候object.username的值已经变成 b了,而password还没有改变
System.out.println(object.getUsername() + " -- " + object.getPassword());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
运行结果:
b -- aa
*/
}
4.
使用 return 停止线程,将 interrupt() 与 return 结合使用也能实现停止线程的效果
public class MyThread extends Thread {
@Override
public void run() {
while (true) {
if (this.isInterrupted()) {
System.out.println("线程停止了!");
return;
}
System.out.println("timer = " + System.currentTimeMillis());
}
}
}
public class Test {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
运行结果:
timer = 1503565757740
timer = 1503565757740
timer = 1503565757740
timer = 1503565757740
timer = 1503565757740
timer = 1503565757740
timer = 1503565757740
线程停止了!
*/
}
虽然return 也可以停止线程,但还是
建议使用“抛异常”法来实现线程的停止,因为在 catch 块中可以对异常的信息进行相关的处理,而且使用异常流能更好、更方便地控制程序的运行流程,不至于代码中出现很多个 return;造成污染。