Java终止线程的四种方法

线程终止常用的四种方式:
终止线程的第一种方式:等待run()或者是call()方法执行完毕
终止线程的第二种方式:设置共享变量,如boolean flag。flag作为线程是否继续执行的标志
终止线程的第三种方式:利用Thread类提供的interrupt()和InterruptedException。
终止线程的第四种方式:利用Thread类提供的interrupt()和isInterrupted()。

问题引出

考虑下面这段程序:

public class MyThread {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new ThreadImpl();
        thread.start();
    }
}

class ThreadImpl extends Thread {
    private static double value = 0;
    int i = 0, j = 0;

    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
        while (i++ < Integer.MAX_VALUE)
            while (j++ < Integer.MAX_VALUE)
                value += 0.1;
        System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
    }
}

线程的核心任务是value自增0.1,但是有两层循环。

终止线程的第一种方式:等待run()或者是call()方法执行完毕,线程自然就结束了(这里run()执行时间太长,不能忍)。
但是很多时候,需要在线程执行过程中终止线程,老版JDK的Thread类提供stop()方法,JDK1.8以后已经被标记为depecated,仍然可以终止线程(已测试),但不建议使用,具体原因网上很多。知道是已废弃的就别用了。。。

终止线程的第二种方式:设置共享变量,如boolean flag。
flag作为线程是否继续执行的标志,属于线程所有。根据需要可以设定为static变量或者实例变量,最好用volatile关键字修饰,这样可以保证flag在线程间的可见性。

如下代码,当flag为true时,线程执行,当需要终止线程时,只需要将该线程对象的flag = false;

public class MyThread {
    public static void main(String[] args) throws InterruptedException {
        ThreadImpl thread = new ThreadImpl();
        thread.start();
        //do something
        thread.flag = false;
    }
}

class ThreadImpl extends Thread {
    private static double value = 0;
    public volatile boolean flag = true;//也可以定义为private,然后利用setter进行赋值
    int i = 0, j = 0;

    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
        while (i++ < Integer.MAX_VALUE && flag)
            while (j++ < Integer.MAX_VALUE && flag)
                value += 0.1;
        System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
    }
}

终止线程的第三种方式:利用Thread类提供的interrupt()和InterruptedException。
需要注意的是,thread.interrupt()只是会设置thread的interrupt flag,而不会正真的终止线程,因此在thread.interrupt()后,可以利用wait、sleep、join等操作收到interrupt()时会抛出InterruptedException异常的特性来终止线程,try … catch…

try{
        //do something
    }catch(InterruptedException e){
        //do something after interruption
    }

示例代码如下:

 public class MyThread {
    public static void main(String[] args) {
        ThreadImpl thread = new ThreadImpl();
        thread.start();
        thread.interrupt();
        if (thread.isInterrupted())
            System.out.println("线程被中断");
    }
}

class ThreadImpl extends Thread {
    public static double value = 0;
    int i = 0, j = 0;

    @Override
    public void run() {
        try {
            System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
            while (i++ < Integer.MAX_VALUE) {
                value += 0.1;
                Thread.sleep(1000);
            }
            System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
        } catch (InterruptedException e) {
            System.out.println("发生中断时, value = " + value);
            e.printStackTrace();
        }
    }
}

输出如下:

线程被中断
线程 Thread-0 执行之前, value = 0.0
发生中断时, value = 0.1
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at threadPool.ThreadImpl.run(MyThread.java:25)

终止线程的第四种方式:利用Thread类提供的interrupt()和isInterrupted()。

public class MyThread {
    public static void main(String[] args) {
        ThreadImpl thread = new ThreadImpl();
        thread.start();
        thread.interrupt();
    }
}

class ThreadImpl extends Thread {
    public static double value = 0;
    int i = 0;

    @Override
    public void run() {

        System.out.println("线程 " + Thread.currentThread().getName() + " 执行之前, value = " + value);
        while (i++ < Integer.MAX_VALUE) {
            value += 0.1;
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 执行之后, value = " + value);
        if (this.isInterrupted()) {
            System.out.println("线程被中断");
            return;
        }
    }
}

输出如下

线程 Thread-0 执行之前, value = 0.0
线程 Thread-0 执行之后, value = 2.1474835660588232E8
线程被中断

以上四种方式中,需要根据实际情况来决定采用何种方式终止线程。
1. 如果线程中存在循环,可用共享变量的方式;
2. 如果需要线程发生终端时返回一些属性,那么建议采用interrupt()+isInterrupted()的方式;
3. 如果线程中存在sleep\wait\join或者其他io操作,则可采用interrupt()+捕获InterruptedException的方式;

补充:关于interrupt
一下是JDK1.8中关于interrupt的实现与说明。
简单的说:
1. 当thread被wait(),sleep(),join()阻塞时,线程状态被清理,同时会收到InterruptedException;
2. 当thread被io,nio阻塞时,也会收到异常;
3. 当1,2都没发生时,thread的 interrupt status被set。

/**
     * Interrupts this thread.
     *
     * <p> Unless the current thread is interrupting itself, which is
     * always permitted, the {@link #checkAccess() checkAccess} method
     * of this thread is invoked, which may cause a {@link
     * SecurityException} to be thrown.
     *
     * <p> If this thread is blocked in an invocation of the {@link
     * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
     * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
     * class, or of the {@link #join()}, {@link #join(long)}, {@link
     * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
     * methods of this class, then its interrupt status will be cleared and it
     * will receive an {@link InterruptedException}.
     *
     * <p> If this thread is blocked in an I/O operation upon an {@link
     * java.nio.channels.InterruptibleChannel InterruptibleChannel}
     * then the channel will be closed, the thread's interrupt
     * status will be set, and the thread will receive a {@link
     * java.nio.channels.ClosedByInterruptException}.
     *
     * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
     * then the thread's interrupt status will be set and it will return
     * immediately from the selection operation, possibly with a non-zero
     * value, just as if the selector's {@link
     * java.nio.channels.Selector#wakeup wakeup} method were invoked.
     *
     * <p> If none of the previous conditions hold then this thread's interrupt
     * status will be set. </p>
     *
     * <p> Interrupting a thread that is not alive need not have any effect.
     *
     * @throws  SecurityException
     *          if the current thread cannot modify this thread
     *
     * @revised 6.0
     * @spec JSR-51
     */
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值