停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。在java中有以下3种方法可以终止正在运行的线程。正如书中所说。
停止不了的线程:
interrupt()方法的使用效果并不像for+break语句那样,马上就停止循环。调用interrupt方法是在当前线程中打了一个停止标志,并不是真的停止线程。
*另外虽然我在main线程中调用thread.interrupt();
,但是线程并么有真正的停止,看输出结果,子线程仍然将500000次循环执行完成。*如下图:
先demo演示下interrupted()方法:
从控制台打印结果,可以看出,线程并未停止,这样证明interrupted的方法解释,测试当前线程是否已经中断,这个当前线程是指main线程,它从未中断过,所以打印两个false;
那么如何在main线程中产生中断效果,做出如下改动:
我特地在主线程中让其休息十秒后打印end,
从结果可以看出,mian线程确实被打断了,但是为什么第二个值是false?
官方是这样解释interrupted方法的:
- 如果要连续调用此方法两次,则第二次调用将返回false(除非当前线程在第一次调用清除其中断状态之后且在第二次调用检查其状态之前再次中断)。
所以在第一次调用interruped()方法后,会将其中断状态清除,所以下一次在调用会返回false。
在来看看isInterrupted()方法
isInterrupted()方法,并没有清除状态标志,所以打印两个true。
所以总结下:
- interrupted():测试当前线程是否是终端中状态,执行后具有将状态标志清除为false的功能。
- isInterruped():测试线程Thread对象是否已经是中断状态,但不清除状态标志。
如何停止线程:
- 异常法
public class MyThread extends Thread {
public void run(){
super.run();
for(int i=0; i<500000; i++){
if(this.interrupted()) {
System.out.println("线程已经终止, for循环不再执行");
break;
}
System.out.println("i="+(i+1));
}
}
}
publicclass Run {
public static void main(String args[]){
Thread thread = new MyThread();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
...
i=202053
i=202054
i=202055
i=202056
线程已经终止, for循环不再执行
上面的示例虽然停止了线程,但如果for语句下面还有语句,还是会继续运行的。看下面的例子:
public class MyThread extends Thread {
public void run(){
super.run();
for(int i=0; i<500000; i++){
if(this.interrupted()) {
System.out.println("线程已经终止, for循环不再执行");
break;
}
System.out.println("i="+(i+1));
}
System.out.println("这是for循环外面的语句,也会被执行");
}
}
...
i=180136
i=180137
i=180138
i=180139
线程已经终止, for循环不再执行
这是for循环外面的语句,也会被执行
如何解决语句继续运行的问题呢?看一下更新后的代码:
publicclass MyThread extends Thread {
public void run(){
super.run();
try {
for(int i=0; i<500000; i++){
if(this.interrupted()) {
System.out.println("线程已经终止, for循环不再执行");
throw new InterruptedException();
}
System.out.println("i="+(i+1));
}
System.out.println("这是for循环外面的语句,也会被执行");
} catch (InterruptedException e) {
System.out.println("进入MyThread.java类中的catch了。。。");
e.printStackTrace();
}
}
}
...
i=203798
i=203799
i=203800
线程已经终止, for循环不再执行
进入MyThread.java类中的catch了。。。
java.lang.InterruptedException
at thread.MyThread.run(MyThread.java:13)
2.在沉睡中停止
publicclass MyThread extends Thread {
public void run(){
super.run();
try {
System.out.println("线程开始。。。");
Thread.sleep(200000);
System.out.println("线程结束。");
} catch (InterruptedException e) {
System.out.println("在沉睡中被打断, 进入catch, 调用isInterrupted()方法的结果是:" + this.isInterrupted());
e.printStackTrace();
}
}
}
运行结果:
线程开始。。。
在沉睡中被打断, 进入catch, 调用isInterrupted()方法的结果是:false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at thread.MyThread.run(MyThread.java:12)
3.暴力停止
使用stop()方法停止线程则是非常暴力的
public class MyThread extends Thread {
privateint i = 0;
public void run(){
super.run();
try {
while (true){
System.out.println("i=" + i);
i++;
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
publicclass Run {
public static void main(String args[]) throws InterruptedException {
Thread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.stop();
}
}
运行结果:
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
Process finished with exit code 0
stop()方法以及作废,因为如果强制让线程停止有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象进行了解锁,导致数据得不到同步的处理,出现数据不一致的问题。
释放锁的不良后果
package com.second.app.thread.interruptd;
/**
* @Author soul yzg
* @Date 2021/2/16 20:07
* 努力学习 天天进步
*/
public class Run {
public static void main(String[] args) {
try {
SynchronizedObject synchronizedObject = new SynchronizedObject();
MyThread thread = new MyThread(synchronizedObject);
thread.start();
Thread.sleep(500);
thread.stop();
System.out.println("synchronizedObject userName: "+synchronizedObject.getUserName());
System.out.println("synchronizedObject password: "+synchronizedObject.getPassword());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.second.app.thread.interruptd;
/**
* @Author soul yzg
* @Date 2021/2/16 20:06
* 努力学习 天天进步
*/
public class MyThread extends Thread {
private SynchronizedObject synchronizedObject;
public MyThread(SynchronizedObject synchronizedObject){
this.synchronizedObject =synchronizedObject;
}
@Override
public void run() {
synchronizedObject.printString("admin","admin");
}
}
package com.second.app.thread.interruptd;
/**
* @Author soul yzg
* @Date 2021/2/16 20:02
* 努力学习 天天进步
*/
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;
}
synchronized public void printString(String userName,String password) {
try {
this.userName = userName;
Thread.sleep(100000);
this.password =password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
由于线程强制停止,导致数据不一致性。