Java随笔-线程stop与interrupt

概述

Java中关于线程停止提供了stop和interrupt两种方式,本文探究一下两者之间的不同。

分析

stop
   /**
     * Forces the thread to stop executing.
     ...
     */
    @Deprecated(since="1.2")
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // The VM can handle all thread states
        stop0(new ThreadDeath());
    }

关于stop()的注释有很多,文中就不一一展示,大致如下:

  • 该方式会强制停止线程。类似于电脑关机的时候没有点关机按钮,而是直接拔掉电源。
  • 若是使用了security manager,或者还有其他线程,关掉的是其他线程,而不是当前线程,则可能会造成SecurityException。
  • 若当前线程正在做其他异常操作,调用该方法会抛出ThreadDeath(一般用于重要的清除操作)异常,无法确定真正的异常。
  • 该方法可以停止尚未启动的线程,若是线程又被启动了,则会马上停止。
  • 该方法天然不安全,调用时会释放所有已上锁的monitors的锁,可能会导致无法意料的错误。
  • @Deprecated(since=“1.2”)表明该方法已被废弃。

总而言之,该方法太粗暴,会导致好多好多错误,有些是莫名其妙的,有些可能会造成更大的错误,而且大多数情况下解决不了,所以能不用就尽量别用。

interrupt

相比于stop(),interrupt()较为温和。

    public void interrupt() {
        if (this != Thread.currentThread()) {
            checkAccess();

            // thread may be blocked in an I/O operation
            synchronized (blockerLock) {
                Interruptible b = blocker;
                if (b != null) {
                    interrupted = true;
                    interrupt0();  // inform VM of interrupt
                    b.interrupt(this);
                    return;
                }
            }
        }
        interrupted = true;
        // inform VM of interrupt
        interrupt0();
    }

该方法注释也有很多。

  • 通常用于自己中断自己,也可能会抛出SecurityException异常。
  • 若是线程被阻塞,比如调用了wait()、join()、sleep(long),中断状态会被清除,并且会收到中断异常InterruptedException。
  • 若是阻塞了I/O操作,InterruptibleChannel会被关闭,则线程中断状态会被重新设置,也会收到ClosedByInterruptException。
  • 若是线程没有存活,调用该方法也不会有任何副作用。

代码中最重要的变化是添加了blockerLock和interrupted,也就是调用该方法后,若该线程会被加上blockerLock锁,同时会被标记上中断中(interrupted = true),意味着线程任务若是没有执行完,会等到任务执行完后再关闭,只是标记该线程需要中断了,并不保证一定会中断,也可能完全不会中断,因为线程之间是协作式的,不是抢占式的。类似于正常关掉电脑,电脑会等所有任务都关闭后再关机,若是遇见更新或无法中断的任务,该电脑就一直无法关机。

interrupted与isInterrupted

与interrupt()相似的还有interrupted()和isInterrupted()。

interrupted
    /**
     * 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).
     *
     * @return  {@code true} if the current thread has been interrupted;
     *          {@code false} otherwise.
     * @see #isInterrupted()
     * @revised 6.0, 14
     */
    public static boolean interrupted() {
        Thread t = currentThread();
        boolean interrupted = t.interrupted;
        // We may have been interrupted the moment after we read the field,
        // so only clear the field if we saw that it was set and will return
        // true; otherwise we could lose an interrupt.
        if (interrupted) {
            t.interrupted = false;
            clearInterruptEvent();
        }
        return interrupted;
    }

观察代码会发现:调用静态interrupted(),该方法会将正在中断的线程标志重新设为false,并清除中断事件。
测试:

    public static void main(String[] args) {
        ThreadPattern threadPattern = new ThreadPattern();
        // 开启
        threadPattern.start();
        // 中断
        threadPattern.interrupt();
    }


    /**
     * Thread扩展类
     */
    private static class ThreadPattern extends Thread{

        @Override
        public void run() {
            super.run();
            System.out.println(Thread.currentThread().getName() + "isInterrupted前:" + isInterrupted());
            //
            interrupted();
            System.out.println(Thread.currentThread().getName() + "isInterrupted后:" + isInterrupted());

        }
    }

结果:

Thread-0isInterrupted前:true
Thread-0isInterrupted后:false

对比结果发现:调用threadPattern.interrupt()后isInterrupted状态为true,调用interrupted()后,isInterrupted状态变为false。确实改变了线程的中断状态。这样设计的目的可能是防止某些非常重要的任务不被中断吧。

isInterrupted
    /**
     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     *
     * @return  {@code true} if this thread has been interrupted;
     *          {@code false} otherwise.
     * @see     #interrupted()
     * @revised 6.0, 14
     */
    public boolean isInterrupted() {
        return interrupted;
    }

该方法就是返回线程的终止状态。
测试:

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        ThreadPattern threadPattern = new ThreadPattern();
        // 开启
        threadPattern.start();
        // 中断
        System.out.println(threadPattern.getName() + "isInterrupted前:" + threadPattern.isInterrupted());
        threadPattern.interrupt();
        System.out.println(threadPattern.getName() + "isInterrupted后:" + threadPattern.isInterrupted());
    }

    /**
     * Thread扩展类
     */
    private static class ThreadPattern extends Thread{

        @Override
        public void run() {
            super.run();
            System.out.println(Thread.currentThread().getName() + "isInterrupted:" + isInterrupted());
        }
    }

结果:

Thread-0isInterrupted前:false
Thread-0isInterrupted:false
Thread-0isInterrupted后:true

结果发现,isInterrupted()只是返回线程中断状态,没有其他任何操作。但线程中若是有抛出中断异常InterruptedException的话,线程的中断状态会被改为false;
测试:

    private static class ThreadPattern extends Thread{

        @Override
        public void run() {
            super.run();
            System.out.println(getName() + ",isInterrupted前:" + isInterrupted());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + ",isInterrupted后:" + isInterrupted());
        }
    }

结果:

Thread-0,isInterrupted前:true
Thread-0,isInterrupted后:false
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at thread.ThreadTest3$ThreadPattern.run(ThreadTest3.java:30)

线程sleep(1000)后,isInterrupted由原来的true变成了false,这样做可能是为了留出缓冲时间用于处理异常,开发中可以在异常处理中进行其他操作。若是还想继续中断,再次调用interrupt()即可。
测试:

    /**
     * Thread扩展类
     */
    private static class ThreadPattern extends Thread{

        @Override
        public void run() {
            super.run();
            System.out.println(getName() + ",isInterrupted前:" + isInterrupted());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(getName() + ",isInterrupted后:" + isInterrupted());
//                // 再次中断
                interrupt();
            }
            System.out.println(getName() + ",isInterrupted后2:" + isInterrupted());
        }
    }

结果:

Thread-0,isInterrupted前:true
Thread-0,isInterrupted后:false
Thread-0,isInterrupted后2:true
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at thread.ThreadTest3$ThreadPattern.run(ThreadTest3.java:30)

说明该线程确实被中断了。

总结

  • stop()太粗暴,不考虑后果,不建议使用。
  • interrupt()处理方式温和,建议使用。
  • interrupted()会清除线程中断状态。
  • isInterrupted()只返回线程中断状态。
  • 线程出现InterruptedException(wait、sleep、interrupt、interrupted),线程中断状态会被清空,想要继续操作,需要再次调用interrupt()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值