如何停止一个线程

上一篇我们介绍了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;停止线程的方式要好,这也是本文推荐的停止线程的方式。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧