如何停止一个线程

/ 多线程 / 没有评论 / 318浏览

上一篇我们介绍了interrupt()、interrupted()、isInterrupted()的使用。这篇我们将用到上一篇所学的内容。我们先看一下简单的线程停止的代码。

/**
* 消息生产者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:31
* @since 1.0.0
*/
public class MessageServer implements Runnable {

@Override
public void run() {
for (int i = 1; i <= 20; i++) {
if (i % 5 == 0) {
if (Thread.interrupted()) {
System.out.println(String.format("线程将要停止:%s", Thread.currentThread().getName()));
break;
}
}
System.out.println(String.format("i%s", i));
}
}
}
/**
* 消息消费者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:41
* @since 1.0.0
*/
public class MessageClient {
public static void main(String[] args) throws InterruptedException {
MessageServer messageServer = new MessageServer();
Thread thread = new Thread(messageServer);
thread.start();
thread.interrupt();
}
}
i:1
i:2
i:3
i:4
线程将要停止:Thread-0

我们知道在线程调用start()方法时,如果获取到了CPU的执行权就会调用线程类的run()方法去执行。换句话说就是线程就是去执行run()方法里的代码的。如果run()方法执行完了,那当前线程也就执行完了。所以我们在上述的代码中添加了一个break;结束循环的语句,循环结束了run()方法也就结束了,线程也就停止了。貌似看没有问题,但这里有一个小的缺陷,就是如果run()方法里的循环外还有代码时,那么循环下面的代码还是要执行的,它要执行run()方法也就是还没有执行完,run()方法没有执行完,当前线程也就不会停止。所以我们上述结束线程的代码也就不正确了。我们看下面的代码来演示这个结果。

/**
* 消息生产者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:31
* @since 1.0.0
*/
public class MessageServer implements Runnable {

@Override
public void run() {
for (int i = 1; i <= 20; i++) {
if (i % 5 == 0) {
if (Thread.interrupted()) {
System.out.println(String.format("线程将要停止:%s", Thread.currentThread().getName()));
break;
}
}
System.out.println(String.format("i%s", i));
}
for (int z = 10; z > 0; z--) {
System.out.println(String.format("run()方法还在执行:%s", z));
}
}
}
/**
* 消息消费者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:41
* @since 1.0.0
*/
public class MessageClient {
public static void main(String[] args) throws InterruptedException {
MessageServer messageServer = new MessageServer();
Thread thread = new Thread(messageServer);
thread.start();
thread.interrupt();
}
}
i:1
i:2
i:3
i:4
线程将要停止:Thread-0
run()方法还在执行:10
run()方法还在执行:9
run()方法还在执行:8
run()方法还在执行:7
run()方法还在执行:6
run()方法还在执行:5
run()方法还在执行:4
run()方法还在执行:3
run()方法还在执行:2
run()方法还在执行:1

我们看到了虽然循环结束了,但该线程还没有结束,因为循环下面还有一个循环它还要继续执行。显示这种用break;方式停止线程的方法是有问题的。那么我们看另一种停止线程的方式。

/**
* 消息生产者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:31
* @since 1.0.0
*/
public class MessageServer implements Runnable {

@Override
public void run() {
for (int i = 1; i <= 20; i++) {
if (i % 5 == 0) {
if (Thread.interrupted()) {
System.out.println(String.format("线程将要停止:%s", Thread.currentThread().getName()));
return;
}
}
System.out.println(String.format("i%s", i));
}
for (int z = 10; z > 0; z--) {
System.out.println(String.format("run()方法还在执行:%s", z));
}
}
}
/**
* 消息消费者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:41
* @since 1.0.0
*/
public class MessageClient {
public static void main(String[] args) throws InterruptedException {
MessageServer messageServer = new MessageServer();
Thread thread = new Thread(messageServer);
thread.start();
thread.interrupt();
}
}
i:1
i:2
i:3
i:4
线程将要停止:Thread-0

这样看我们的确停止了一个线程,因为我们将run()方法中的break;语句换成了return;我们知道return;语句是结束一个方法的意思,当run()方法都结束了,那么线程也就自然而然的停止了。虽然这样的方式可以停止一个线程但我们并不推荐这样做,因为如果采用return;方式的话,我们并不能在线程停止时做出相应的业务处理。还有一种方式可以停止一个线程那就是抛出一个异常。我们看下面的代码:

/**
* 消息生产者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:31
* @since 1.0.0
*/
public class MessageServer implements Runnable {

@Override
public void run() {
try {
for (int i = 1; i <= 20; i++) {
if (i % 5 == 0) {
if (Thread.interrupted()) {
System.out.println(String.format("线程将要停止:%s", Thread.currentThread().getName()));
throw new InterruptedException();
}
}
System.out.println(String.format("i%s", i));
}
for (int z = 10; z > 0; z--) {
System.out.println(String.format("run()方法还在执行:%s", z));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 消息消费者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:41
* @since 1.0.0
*/
public class MessageClient {
public static void main(String[] args) throws InterruptedException {
MessageServer messageServer = new MessageServer();
Thread thread = new Thread(messageServer);
thread.start();
thread.interrupt();
}
}
java.lang.InterruptedException
i:1
	at MessageServer.run(MessageServer.java:19)
i:2
	at java.lang.Thread.run(Thread.java:745)
i:3
i:4
线程将要停止:Thread-0

我们看程序虽然抛出了异常但线程确实停止了。正常开发时,我们可以在异常的catch方法中添加相应的处理逻辑来处理线程被停止时的相关业务。下面我们演示当线程停止时,恢复该线程让它继续执行。

/**
* 消息生产者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:31
* @since 1.0.0
*/
public class MessageServer implements Runnable {

@Override
public void run() {
try {
for (int i = 1; i <= 20; i++) {
if (i % 5 == 0) {
if (Thread.interrupted()) {
System.out.println(String.format("线程将要停止:%s", Thread.currentThread().getName()));
throw new InterruptedException();
}
}
System.out.println(String.format("i%s 线程:%s", i, Thread.currentThread().getName()));
}
for (int z = 10; z > 0; z--) {
System.out.println(String.format("run()方法还在执行:%s 线程:%s", z, Thread.currentThread().getName()));
}
} catch (InterruptedException e) {
MessageServer messageServer = new MessageServer();
Thread recoverThread = new Thread(messageServer);
recoverThread.start();
}
}
}
/**
* 消息消费者
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-13 16:41
* @since 1.0.0
*/
public class MessageClient {
public static void main(String[] args) throws InterruptedException {
MessageServer messageServer = new MessageServer();
Thread thread = new Thread(messageServer);
thread.start();
thread.interrupt();
}
}
i:1 线程:Thread-0
i:2 线程:Thread-0
i:3 线程:Thread-0
i:4 线程:Thread-0
线程将要停止:Thread-0
i:1 线程:Thread-1
i:2 线程:Thread-1
i:3 线程:Thread-1
i:4 线程:Thread-1
i:5 线程:Thread-1
i:6 线程:Thread-1
i:7 线程:Thread-1
i:8 线程:Thread-1
i:9 线程:Thread-1
i:10 线程:Thread-1
i:11 线程:Thread-1
i:12 线程:Thread-1
i:13 线程:Thread-1
i:14 线程:Thread-1
i:15 线程:Thread-1
i:16 线程:Thread-1
i:17 线程:Thread-1
i:18 线程:Thread-1
i:19 线程:Thread-1
i:20 线程:Thread-1
run()方法还在执行:10 线程:Thread-1
run()方法还在执行:9 线程:Thread-1
run()方法还在执行:8 线程:Thread-1
run()方法还在执行:7 线程:Thread-1
run()方法还在执行:6 线程:Thread-1
run()方法还在执行:5 线程:Thread-1
run()方法还在执行:4 线程:Thread-1
run()方法还在执行:3 线程:Thread-1
run()方法还在执行:2 线程:Thread-1
run()方法还在执行:1 线程:Thread-1

因为我们在catch中重新开启了一个新线程去执行了run()方法,这就保证了这个线程类不会被外部调用者给停止执行。当然也可以处理一些不同的业务逻辑,方便用户去处理,这显示要比直接用return;停止线程的方式要好,这也是本文推荐的停止线程的方式。