如何停止一个Java线程

来源:互联网 发布:二叉树反转python 编辑:程序博客网 时间:2024/05/18 00:56

最近在做项目,遇到一个问题:如果停止一个Java线程。请教了很多人,也查了不少资料,现在总结梳理一下。


Java推荐的标准方法:使用interrupt终止线程
如何使用interrupt中断一个线程?通常的做法是在线程外部调用interrupt方法,线程内部会接收到相应异常,然后在异常处理中安全退出线程。请看下面的例子:

public class MyThread implements Runnable{    private Thread runner = new Thread(this, "runner");    public void start()    {        runner.start();    }    public void interrupt()    {        runner.interrupt();    }    @Override    public void run()    {        while(true)        {            try            {                Thread.sleep(1000);                System.out.println("thread is running.");            }            catch(Exception e)            {                System.out.println("thread exit.");                         break;            }        }    }    public static void main(String[] args)     {        MyThread myThread = new MyThread();             try        {            myThread.start();            Thread.sleep(5000);            myThread.interrupt();        }        catch(Exception e)        {            System.out.println(e);        }    }}

那么,是否调用interrupt方法,线程内部都会收到响应异常?其实不是这样,如果线程内部没有调用sleep/wait/join等方法,线程是不会接收到响应异常的。请看看下面的例子。

public class MyThread implements Runnable{    private Thread runner = new Thread(this, "runner");    public void start()    {        runner.start();    }    public void interrupt()    {        runner.interrupt();    }    @Override    public void run()    {        try        {            while(true)            {                int a = 1;            }        }        catch(Exception e)        {            System.out.println(e);        }    }    public static void main(String[] args)     {        MyThread myThread = new MyThread();             try        {            myThread.start();            Thread.sleep(5000);            myThread.interrupt();        }        catch(Exception e)        {            System.out.println(e);        }    }}

参考JDK文档可知,调用interrupt终止线程可分为以下几种情况:
a> 如果线程被阻塞在wait/sleep/join等方法调用,调用interrupt方法,线程内部会接受到InterruptedException
b> 如果线程被阻塞在基于interruptible channel实现的I/O操作,调用interrrupt方法,通道会被关闭,线程内部会接收到ClosedByInterruptException.
c> 如果线程被阻塞在Selector,selection操作会立刻返回,且返回值非负。
d> 除了上述情况,其他情况Interrupt只会简单是设置中断标识位。
详见:

http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt()

从上面描述可知,这里需要解决两个问题:
对于没有阻塞的方法,使用interrupt如何终止线程;
对于没有基于interruptible channel实现的I/O操作,如果终止线程。


看第一个问题:终止没有阻塞的线程。
对于这类线程,调用interrupt,线程内部不会受到相应异常,只是设置了中断标识,这时候可以通过检测中断标识位,判断是否终止线程。

public class MyThread implements Runnable{    private Thread runner = new Thread(this, "runner");    public void start()    {        runner.start();    }    public void interrupt()    {        runner.interrupt();    }    @Override    public void run()    {        while(true)        {            if(runner.isInterrupted())            {                System.out.println("thread exit.");                break;            }        }    }    public static void main(String[] args)     {        MyThread myThread = new MyThread();             try        {            myThread.start();            Thread.sleep(5000);            myThread.interrupt();        }        catch(Exception e)        {            System.out.println(e);        }    }}

第二个问题:终止没有基于interruptible channel实现的I/O操作。这时候Interrupt方法就无能为力,可以尝试使用Thread.stop,关于stop的使用下面详细讨论


使用stop方法终止线程

使用stop终止线程,线程会被立刻终止掉。如下面代码所示

public class MyThread implements Runnable{    private Thread runner = new Thread(this, "runner");    public void start()    {        runner.start();    }    public void stop()    {        runner.stop();    }    public void interrupt()    {        runner.interrupt();    }    @Override    public void run()    {        try        {            while(true)            {                int a = 1;            }        }        catch(Throwable e)        {            System.out.println(e);        }    }    public static void main(String[] args)     {        MyThread myThread = new MyThread();             try        {            myThread.start();            Thread.sleep(5000);            myThread.stop();        }        catch(Exception e)        {            System.out.println(e);        }    }}

Stop方法现在已经不推荐使用了。详见Java的官方文档,对于不建议使用stop等方法的说明:

http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

主要原因是,使用stop后,线程会立即是否所持有的锁。使用锁的本意通常是为了同步,保证数据的一致性。如果从A账户向B账户转账100元,如果在中间释放了锁,其他线程继续读取数据,很可能出现数据部一致。

    public synchronized void ProcessData(int data)    {        accountA = accountA - data;        accountB = accountB + data;    }

另外,使用stop,线程会受到ThreadDeath的异常,而且这个异常可能发生在任何时候,包括catch和finally。

那么使用stop是否可以终止任何线程?其实不是这样,如下面代码所示:

public class MyThread extends Thread{       @Override    public synchronized void run()    {        try        {            while(true)            {                int a = 1;            }        }        catch(Throwable e)        {            System.out.println(e);        }    }    public static void main(String[] args)     {        MyThread myThread = new MyThread();             try        {            myThread.start();            Thread.sleep(5000);            myThread.stop();        }        catch(Exception e)        {            System.out.println(e);        }           }}

查看Thread.stop的源码可以发现,stop是一个同步方法,需要获取到一个同步锁,以为要线程run方法已占用的了锁,且不释放,所以stop方法一样也无法终止。附Thread.stop源码:

    /**     * @deprecated Method stop is deprecated     */    public final synchronized void stop(Throwable throwable)    {        if(throwable == null)            throw new NullPointerException();        SecurityManager securitymanager = System.getSecurityManager();        if(securitymanager != null)        {            checkAccess();            if(this != currentThread() || !(throwable instanceof ThreadDeath))                securitymanager.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);        }        if(threadStatus != 0)            resume();        stop0(throwable);    }

终止I/O读写的线程:待补充
终止线程池中的线程:待补充
线程创建于任务执行的分离:待补充

参考资料:

http://forward.com.au/javaProgramming/HowToStopAThread.html

http://blog.csdn.net/anhuidelinger/article/details/11746365

http://kdisk-sina-com.iteye.com/blog/835890

http://www.javacoffeebreak.com/articles/network_timeouts/

0 0
原创粉丝点击