Java中断机制

栏目: Java · 发布时间: 5年前

内容简介:Java中断机制为我们提供了一种"试图"停止一个线程的方法。设想我们有一个线程阻塞在一个耗时的I/O中,我们又不想一直等下去,那么我们怎么样才能停止这个线程呢?答案就是Java的中断机制。Java线程的状态包括:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING和TERMINATED总共六种状态:一个线程新建后,在调用该线程的start()方法之前,该线程的状态就是NEW;当线程的start()方法被调用之后,该线程已经准备被CPU调度,此时线程的状态就是RUNNABLE;

Java中断机制为我们提供了一种"试图"停止一个线程的方法。设想我们有一个线程阻塞在一个耗时的I/O中,我们又不想一直等下去,那么我们怎么样才能停止这个线程呢?答案就是 Java 的中断机制。

从Java线程的状态说起

Java线程的状态包括:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING和TERMINATED总共六种状态:

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }
复制代码

一个线程新建后,在调用该线程的start()方法之前,该线程的状态就是NEW;当线程的start()方法被调用之后,该线程已经准备被CPU调度,此时线程的状态就是RUNNABLE;如果一个对象的monitor lock被其他线程获取了,这个时候我们再通过synchronized关键字去获取改对象的monitor lock时,线程就会进入BLOCKED状态;通过调用Thread#join()方法或者Object#wait()方法(不设置超时时间,with no timeout)或者LockSupport#park()方法可以让一个线程从RUNNABLE状态转为WAITING状态;TIMED_WAITING指线程处于等待中,但是这个等待是有期限的(),通过调用Thread#sleep(),Object#wait(long timeout),Thread#join(long timeout),LockSupport#parkNanos(),LockSupport#partUnitl()都可使线程切换到TIMED_WAITING状态。最后一种状态TERMINATED是指线程正常退出或者异常退出后的状态。下面这张图展示了这六种线程状态之间的相互转换关系:

Java中断机制

当线程处于等待状态或者有超时的等待状态时(TIMED_WAITING,WAITING)我们可以通过调用线程的interrupt()方法来中断线程的等待,此时线程会抛InterruptedException异常。例如Thread.sleep()方法: public static native void sleep(long millis) throws InterruptedException; 此方法就会抛出这类异常。 但是当线程处于BLOCKED状态或者RUNNABLE(RUNNING)状态时,调用线程的interrupt()方法也只能将线程的状态位设置为true。停止线程的逻辑需要我们自己去实现。

中断原理

查看java源码可以看到Thread类中提供了跟中断相关的一些方法:

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

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {                                               2
                interrupt0();           // Just to set the interrupt flag  3
                b.interrupt(this);                                         4
                return;
            }
        }
        interrupt0();
    }
复制代码

interrupt()方法用于中断一个线程,首先在第1处中断方法会判断当前caller线程是否具有中断本线程的权限,如果没有权限则抛出SecurityException异常。然后在2处方法会判断阻塞当前线程的对象是否为空,如果不为空,则在3处先设置线程的中断flag为true,然后再由Interruptible对象(例如可以中断的I/O操作)去中断操作。从中我们也可以看到如果当前线程不处于WAITING或者TIMED_WAITING状态,则interrupt()方法也只是仅仅设置了该线程的中断flag为true而已。

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
复制代码

再看interrupted()方法,该方法是一个静态的方法,最终会调用具体线程实例的isInterrupted()方法:

public boolean isInterrupted() {
        return isInterrupted(false);
    }
    
    private native boolean isInterrupted(boolean ClearInterrupted);
复制代码

interrupted()方法第一次调用时会返回当前线程的中断flag,然后就清除了这个状态位,但是isInterrupted()方法不会清除该状态位。因此一个线程中断后,第一次调用interrupted()方法会返回true,第二次调用就返回false,因此第一次调用后该状态位已经被清除了。但是同样一个线程中断后,多次调用isInterrupted()方法都会返回true。这是两者的不同之处,但是两者最终都会调用一个名为isInterrupted的native方法。

中断的处理

java中一般方法申明了throws InterruptedException的就是可以中断的方法,比如:ReentrantLock#lockInterruptibly,BlockingQueue#put,Thread#sleep,Object#wait等。当这些方法被中断后会抛出InterruptedException异常,我们可以捕获这个异常,并实现自己的处理逻辑,也可以不处理,继续向上层抛出异常。但是记住不要捕获异常后什么都不做并且不向上层抛异常,也就是说我们不能" 吞掉 "异常。 对于一些没有抛出InterruptedException的方法的中断逻辑只能由我们自己去实现了。例如在一个大的循环中,我们可以自己判断当前线程的中断状态然后选择是否中断当前操作:

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 循环中检测当前线程的中断状态 
                for (int i = 0; i < Integer.MAX_VALUE && !Thread.currentThread().isInterrupted(); i++) {
                    System.out.println(i);
                }
            }
        });
        thread.start();
        Thread.sleep(100);
        thread.interrupt();
    }
}
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

刘大猫的财富之旅

刘大猫的财富之旅

刘欣、刘大猫 / 新华出版社 / 2017-7-21 / 58.00元

作者刘大猫是一名90后的互联网连环创业者,26岁的他通过互联网创业收获到了财富,不仅仅是物质财富,还有认知的财富。 与其他创业类书籍不通的是,这本书非常真实,务实。书中没有任何大道理鸡汤,作者用平实的语言记录了创业以来遇到的种种事情,变化,困境,以及阶段性的成绩,记录了作者务实,鲜活的创业青春。一起来看看 《刘大猫的财富之旅》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具