interrupt相关的方法

停止当前线程有Thread.stop()方法,但是这个方法已经被标记为@Deprecated了,那么替代它的方法是什么呢?interrupt。

它有三个长得很像的方法:interrupt(),isInterrupted(),interrupted()。


第一:MyThreadA.interrupt():给MyThreadA线程设置一个中断标志。(注意,这里不同于stop()方法,并不是直接中断)。如果MyThreadA正在处于阻塞状态,那么MyThreadA线程将抛出一个 InterruptedException异常中断线程。

那么什么是阻塞状态呢?大佬的博客是这样说的:

如果线程被Object.wait, Thread.joinThread.sleep三种方法之一阻塞,此时调用该线程的interrupt()方法,那么该线程将抛出一个 InterruptedException中断异常(该线程必须事先预备好处理此异常),从而提早地终结被阻塞状态。如果线程没有被阻塞,这时调用 interrupt()将不起作用,直到执行到wait(),sleep(),join()时,才马上会抛出 InterruptedException。

public class Test {
    public static void main(String[] args) throws InterruptedException {
        RunTest rt = new RunTest();
        Thread t = new Thread(rt);
        t.start();
        t.interrupt();
    }
}

class RunTest implements Runnable {
    @Override
    public void run() {
        try {
            for (long i = 0; i < 10000000L; i++) {
                System.out.println("I'm doing a time consuming task");
            }
//            TimeUnit.SECONDS.sleep(2); 这条语句会被中断,抛出java.lang.InterruptedException异常
            System.out.println("Thread finished.");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Thread execption.");
        }
    }
}

RunTest线程是在循环一个非常大的数字,但它没有阻塞,所以interrupt()方法对它无效,RunTest线程会被正常执行完,打印Thread finished.


第二:MyThreadA.isInterrupted():判断MyThreadA线程是否设置了中断标记。需要注意的是,如果线程被中断且已经抛出了异常,它会清除中断标志。


public class Test {
    public static void main(String[] args) throws InterruptedException {
        RunTest rt = new RunTest();
        Thread t = new Thread(rt);
        t.start();
        t.interrupt();
        System.out.println(t.isInterrupted());
    }
}

class RunTest implements Runnable {
    @Override
    public void run() {
        try {
            TimeUnit.SECONDS.sleep(2); //这条语句会被中断,抛出java.lang.InterruptedException
            System.out.println("Thread finished.");
        } catch (Exception e) {
            System.out.println("Thread execption.");
            //已经抛出了异常,会清除中断标记
            System.out.println("isInterrupted? -->" + Thread.currentThread().isInterrupted());
        }
    }
}


第三:Thread.interrupted():这个是静态方法,直接Thread.interrupted()就好了,它会判断当前线程是否被设置了中断标志,并且清除中断标志。重点:静态方法,当前线程,清除中断标志。

其实,它和isInterrupted()是很像的,调用的是同一个方法。


    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    /**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

isInterrupted(boolean flag):是否清除中断标记。

看一下interrupted()方法的注释:如果这个方法被成功调用两次,第二次会返回false。

if this method were to be called twice in succession, the
 second call would return false.
public class Test {
    public static void main(String[] args) throws InterruptedException {
        RunTest rt = new RunTest();
        Thread t = new Thread(rt);
        t.start();
        t.interrupt();
    }
}

class RunTest implements Runnable {
    @Override
    public void run() {
        try {
            for (long i = 0; i < 100000L; i++) {
                System.out.println("I'm doing a time consuming task");
            }
            System.out.println("Thread finished.");
            System.out.println("1."+Thread.interrupted());
            System.out.println("2."+Thread.interrupted());
        } catch (Exception e) {
            System.out.println("Thread execption.");
            //已经抛出了异常,会清除中断标记
            System.out.println("isInterrupted? -->" + Thread.currentThread().isInterrupted());
        }
    }
}

 


interrupt相关的三个方法就写完了,那么对于线程执行时间太长,但又不是阻塞的情况,该怎么办呢(例子中很大的for循环)?ThreadPoolExecutor.shutdown(),ThreadPoolExecutor.shutdownNow()以及ThreadPoolExecutor.awaitTermination(long timeout, TimeUnit unit),Future.get()方法都试过了,都不能解决。最后在shutdownNow()方法的注释找到了结果:

* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks.  For example, typical
* implementations will cancel via {@link Thread#interrupt}, so any
* task that fails to respond to interrupts may never terminate.
*

用博主自己的意思润色翻译为:shutdownNow()方法只能尽可能的尝试去停止正在运行的线程任务,但并不保证一定能成功。比如,此方法的典型实现是通过给线程任务添加一个中断标记interrupt。但是呢,如果正在运行的线程任务对interrupt()方法不感冒的话(不属于Object.wait, Thread.join和Thread.sleep阻塞),那么这部分的线程任务是不会停止的。


其实以上列举的方法停止正在运行的线程,都是通过添加中断标记interrupt来实现的。所以对于上面的很大的for循环的例子,目前jdk还没有解决这种问题的方法。当然,Thread.stop()这类官方不推荐的方法我没有尝试,如果同学们有什么好的解决方案,欢迎留言一起探讨~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值