码迷,mamicode.com
首页 > 编程语言 > 详细

如何安全的结束一个正在运行的线程

时间:2016-07-08 19:42:42      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:


背景
java.lang.Thread类包含了一些常用的方法,如:start(), stop(), stop(Throwable) ,suspend(), destroy() ,resume()。通过这些方法,我们可以对线程进行方便的操作,但是这些方法中,只有start()方法得到了保留。

在JDK帮助文档以及Sun公司的一篇文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》中都讲解了舍弃这些方法的原因。

简单来说是因为:使用stop方法虽然可以强行终止正在运行或挂起的线程,但使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。

那么,我们究竟应该如何停止线程呢?
 
使用退出标志
当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的,如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。

public class Test {
    public static volatile boolean exit = false;//退出标志。volatile关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值
    public static void main(String[] args) {
        new Thread() {
            public void run() {
                System.out.println("线程启动了");
                while (!exit) {//死循环,正常情况下是不会停止的
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()));
                }
                System.out.println("线程安全停止了");
            };
        }.start();
        new Thread() {//另开一条线程
            public void run() {
                try {
                    Thread.sleep(1000 * 5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                exit = true;//5秒后更改退出标志的值
            };
        }.start();
    }
}

使用interrupt
如果一个线程由于等待某些事件的发生而被阻塞,又该怎样停止该线程呢?
这种情况经常会发生,比如当一个线程由于需要等候键盘输入而被阻塞,或者调用Thread.join()方法,或者Thread.sleep()方法,在网络中调用ServerSocket.accept()方法,或者调用了DatagramSocket.receive()方法时,都有可能导致线程阻塞,使线程处于处于不可运行状态时,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。
这里我们给出的建议是,不要使用stop()方法,而是使用Thread提供的interrupt()方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码。

使用interrupt方法来终端线程可分为两种情况:
1、线程处于阻塞状态,如Thread.sleep、wait、IO阻塞等情况时。在这种情况下调用interrupt方法后,sleep方法将抛出一个InterruptedException
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            public void run() {
                System.out.println("线程启动了");
                try {
                    Thread.sleep(1000 * 10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("哈哈,被中断了:" + isInterrupted());//这里的结果竟然是false
            }
        };
        thread.start();
        Thread.sleep(1000 * 1);
        thread.interrupt();//注意,此方法不会中断一个正在运行的线程,它的作用是:在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
        Thread.sleep(1000 * 1);
        System.out.println("线程是否被中断:" + thread.isInterrupted());//这里的结果竟然是false
    }
}  

2、使用来判断线程是否被中断
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            public void run() {
                System.out.println("线程启动了");
                while (!isInterrupted()) {
                    System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + "--" + isInterrupted());//调用之后为true
                }
                System.out.println("哈哈,被中断了");
            }
        };
        thread.start();
        Thread.sleep(1000 * 2);
        thread.interrupt();//注意,此方法不会中断一个正在运行的线程,它的作用是:在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
        System.out.println("线程是否被中断:" + thread.isInterrupted());//true
    }
}

不能结束的情况
注意下面这种即使异常也根本不能结束的情况!
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            public void run() {
                System.out.println("线程启动了");
                while (true) {//对于这种情况,即使线程调用了intentrupt()方法并且isInterrupted(),但线程还是会继续运行,根本停不下来!
                    System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + "--" + isInterrupted());//调用之后为true
                }
            }
        };
        thread.start();
        Thread.sleep(1000 * 5);
        thread.interrupt();//注意,此方法不会中断一个正在运行的线程,它的作用是:在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
        while (true) {
            System.out.println("是否被中断:" + thread.isInterrupted());//true
        }
    }
}





如何安全的结束一个正在运行的线程

标签:

原文地址:http://www.cnblogs.com/baiqiantao/p/5654263.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!