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.
     *
     * 

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. * *

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}. * *

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}. * *

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. * *

If none of the previous conditions hold then this thread's interrupt * status will be set.

* *

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(); }

你可能感兴趣的:(Java,多线程并发)