笔者是广州的java程序员,刚毕业半年,工作之余写博客,如果觉得我的文章写得不错,可以关注我的微信公众号(J2彬彬),里面会有更多精彩内容。从2018年8月份开始写博客,希望日后写出更多通俗易懂的技术文章与大家一同分享。
前言
你有没有想过,如何停止一个线程?很多人首先会想到Thread.stop()方法,但是这个方法已经过时,不推荐使用,因为这个方法会带来安全问题,什么安全问题呢?后面会有详细说明。我们先讲讲目前JDK API推荐使用停止线程的方法Thread.interrupt()方法。
Thread.interrupt()
既然不能直接stop线程,那么只有一种方法可以让线程结束,那就是让run方法运结束。 Thread.interrupt()代表的意思是“停止,中止”。但是这个方法需要加入一个判断才可以完成线程的停止。一旦检测到线程处于中断状态,那么就有机会结束run方法。 下面以一个代码示例看看它是如何停止线程的?
一、interrupt()停止线程
package com.bingo.thread.stopThread;
/**
* Created with IntelliJ IDEA.
* Description: 停止线程不推荐使用stop方法,此方法不安全,我们可以使用Thread.interrupt()
* User: bingo
*/
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
myThread.interrupt();
System.out.println("end...");
}
}
class MyThread extends Thread{
@Override
public void run() {
super.run();
for (int i = 0; i < 10000 ; i++) {
if(this.isInterrupted()){
System.out.println("已经是停止状态了,我要退出了");
break;
}
System.out.println("i="+(i+1));
}
}
}
运行结果:
i=1
......
i=3102
i=3103
i=3104
i=3105
i=3106
i=3107
i=3108
end...
已经是停止状态了,我要退出了
运行结果我们可以看到,当myThread线程的循环运行到i=3108的时候,由于线程被中断,而跳出循环,这个例子很好诠释了interrupt方法的作用。
二、interrupt可以清除线程的冻结状态,让线程恢复到可运行的状态上来
package com.bingo.thread.stopThread;
/**
* Created with IntelliJ IDEA.
* Description: interrupt可以清除线程的冻结状态,让线程恢复到可运行的状态上来。
* User: bingo
*/
public class Run2 {
public static void main(String[] args) {
MyThread2 thread = new MyThread2();
thread.start();
thread.interrupt();
System.out.println("main end...");
}
}
class MyThread2 extends Thread{
@Override
public void run() {
System.out.println("run begin...");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
System.out.println("run 在沉睡中被中止,进入catch");
e.printStackTrace();
}
System.out.println("run end...");
}
}
运行结果:
main end...
run begin...
run 在沉睡中被中止,进入catch
run end...
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.bingo.thread.stopThread.MyThread2.run(Run2.java:26)
从运行结果我们可以看到,本来run方法睡眠时间为1000秒,但是打印结果却是瞬间的,其实sleep已经被interrupt方法给打断,此时线程冻结状态被清除,并抛出异常,被catch捕获,打印异常信息。
暴力停止——Stop
下图是JDK API对stop方法的描述,可以看到已过时,不推荐使用,并告诉我们此方法为何不安全?

package com.bingo.thread.stopThread;
/**
* Created with IntelliJ IDEA.
* Description: stop()方法为何不安全?下面例子可解答
* User: bingo
*/
public class StopTest {
public static void main(String[] args) {
try {
SynchrionzedObject object = new SynchrionzedObject();
MyThread3 t = new MyThread3(object);
t.start();
Thread.sleep(500);
t.stop();
System.out.println(object.getUsername()+" "+object.getPassword());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SynchrionzedObject{
private String username = "a";
private String password = "aa";
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public synchronized void printString(String username,String password){
try {
this.username = username;
Thread.sleep(10000);
this.password = password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread3 extends Thread{
private SynchrionzedObject object;
public MyThread3(SynchrionzedObject object){
this.object = object;
}
@Override
public void run() {
object.printString("b", "bb");
}
}
运行结果:
b aa
从上面例子我们可以看到虽然printString方法加了锁,但是run方法运行过程中突然被stop了,锁被释放,MyThread线程只对username进行了赋值,而password赋值动作未执行,此时造成数据不一致。
最后
其实java多线程很多方法内部都是native方法,也就是基于JVM内部实现的,所以我们有必要结合JVM一起学习这部分的内容。技术的进步需要每个小小的积累,才能走得更远,更长久。