停止一个线程意味着任务没有处理完之前放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它,因为这个方法是不安全的,而且已经被废弃。
写在前面:推荐使用异常来实现线程的停止,因为在catch块中还可以将异常向上抛,使线程停止事件得以传播。
interrupt()方法的使用效果并不像for+break语句那样,马上就停止循环。调用interrupt方法是在当前线程中打了一个停止标志,并不是真的停止线程。
package com.linyf.demo.thread.stop;
public class StopThreadTest1 {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
try {
Thread.sleep(500);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread {
public void run(){
for(int i=0; i<500000; i++){
System.out.println("i="+(i+1));
}
}
}
Thread类中有两种方法:
这两个方法的区别:
测试当前线程是否已经中断,当前线程指运行this.interrupted()方法的线程。
package com.linyf.demo.thread.stop;
public class StopTest1 {
public static void main(String[] args) {
Thread thread = new MyThread();
new Thread(() -> thread.run()).start();
try{
Thread.sleep(2000);
thread.interrupt();
System.out.println("stop 1 interrupt:" + thread.interrupted());
System.out.println("stop 2 interrupt:" + thread.interrupted());
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for(int i=0; i<500000; i++){
i++;
}
}
}
运行结果:
StopTest1 中虽然是在thread对象上调用:thread.interrupt(), 后面又使用
来判断thread对象所代表的线程是否停止,但从控制台打印的结果来看,线程并未停止,这也证明了interrupted()方法的解释,测试当前线程是否已经中断。
这个当前线程是main,它从未中断过,所以打印的结果是两个false.
使main线程产生中断效果:
package com.linyf.demo.thread.stop;
public class StopTest2 {
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println("stop 1 interrupt:" + Thread.currentThread().interrupted());
System.out.println("stop 2 interrupt:" + Thread.currentThread().interrupted());
}
}
执行结果:
方法interrupted()的确判断出当前线程是否是停止状态。但为什么第2个布尔值是false呢?
官方帮助文档中对interrupted方法的解释:
测试当前线程是否已经中断。线程的中断状态由该方法清除。也就是说,如果连续两次调用该方法,则第二次调用返回false。
package com.linyf.demo.thread.stop;
public class StopTest3 {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
thread.interrupt();
System.out.println("stop 1 interrupt:" + thread.isInterrupted());
System.out.println("stop 2 interrupt:" + thread.isInterrupted());
}
}
执行结果:
isInterrupted()并未清除状态,所以打印了两个true。
有了前面学习过的知识点,就可以在线程中用if语句来判断一下线程是否是停止状态,如果是停止状态,则后面的代码不再运行即可:
package com.linyf.demo.thread.stop;
public class StopTest4 {
public static void main(String[] args) {
Thread thread = new MyThread1();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread1 extends Thread{
@Override
public void run(){
for(int i=0; i<500000; i++){
if(this.interrupted()) {
System.out.println("线程已经终止, for循环不再执行");
break;
}
System.out.println("i="+(i+1));
}
}
}
执行结果:
如果for语句下面还有语句,还是会继续运行:
执行结果:
使用异常解决语句继续运行:
package com.linyf.demo.thread.stop;
public class StopTest4 {
public static void main(String[] args) {
Thread thread = new MyThread1();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread1 extends Thread{
@Override
public void 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("捕获到了线程终端异常。。。");
e.printStackTrace();
}
}
}
package com.linyf.demo.thread.stop;
public class StopTest5 {
public static void main(String[] args) {
Thread thread = new MyThread2();
thread.start();
thread.interrupt();
}
}
class MyThread2 extends Thread {
@Override
public void run() {
try {
System.out.println("线程开始。。。");
Thread.sleep(200000);
System.out.println("线程结束。");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止, 进入catch, 调用isInterrupted()方法的结果是:" + this.interrupted());
e.printStackTrace();
}
}
}
执行结果:
结论:如果在sleep状态下停止线程,会进入catch语句,并且清除停止状态。
package com.linyf.demo.thread.stop;
public class StopTest6 {
public static void main(String[] args) {
Thread thread = new MyThread3();
thread.start();
}
}
class MyThread3 extends Thread {
@Override
public void run() {
try {
System.out.println("线程开始。。。");
this.interrupt();
Thread.sleep(2000);
System.out.println("线程结束。");
} catch (InterruptedException e) {
System.out.println("先停止,再遇到sleep,进入catch异常");
e.printStackTrace();
}
}
}
使用stop()方法停止线程是非常暴力的:
package com.linyf.demo.thread.stop;
public class StopTest7 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new MyThread4();
thread.start();
Thread.sleep(2000);
thread.stop();
}
}
class MyThread4 extends Thread {
private static int i = 0;
@Override
public void run() {
while (true) {
i++;
System.out.println(i);
}
}
}
调用stop()方法时会抛出java.lang.ThreadDeath异常,但是通常情况下,此异常不需要显示地捕捉。
package com.linyf.demo.thread.stop;
public class StopTest8 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new MyThread5();
thread.start();
}
}
class MyThread5 extends Thread {
private static int i = 0;
@Override
public void run() {
try {
this.stop();
} catch (ThreadDeath e) {
System.out.println("调用stop方法, 进入异常catch");
e.printStackTrace();
}
}
}
使用stop()释放锁将会给数据造成不一致性的结果。如果出现这样的情况,程序处理的数据就有可能遭到破坏,最终导致程序执行的流程错误:
package com.linyf.demo.thread.stop;
public class StopTest9 {
public static void main(String[] args) throws InterruptedException {
SynchronizedObject synchronizedObject = new SynchronizedObject();
Thread thread = new MyThread6(synchronizedObject);
thread.start();
Thread.sleep(500);
thread.stop();
System.out.println(synchronizedObject.getName() + " " + synchronizedObject.getPassword());
}
}
class MyThread6 extends Thread {
private SynchronizedObject synchronizedObject;
public MyThread6(SynchronizedObject synchronizedObject){
this.synchronizedObject = synchronizedObject;
}
public void run(){
synchronizedObject.printString("b", "bb");
}
}
class SynchronizedObject {
private String name = "a";
private String password = "aa";
public synchronized void printString(String name, String password){
try {
this.name = name;
Thread.sleep(100000);
this.password = password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
将方法interrupt()与return结合使用也能实现停止线程的效果:
package com.linyf.demo.thread.stop;
public class StopTest10 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new MyThread7();
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
}
class MyThread7 extends Thread {
@Override
public void run(){
int i = 0;
while (true){
i++;
if(this.interrupted()){
System.out.println("线程被停止了。i="+i);
return;
}
System.out.println("aaaa");
}
}
}