JAVA线程中断

几个API

判断线程是否被中断

while(!Thread.currentThread().isInterrupted() && more work to do){
    do more work
}

JDK源代码分析

    public void interrupt() {
        //如果不是本线程,那么需要检查是否拥有权限。如果没有,抛出SecurityException
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {//本线程对象所持有的锁,用于防止并发出错。
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag(设置标识位,native方法)
                b.interrupt(this);//真正打断进程的方法
                return;
            }
        }
        interrupt0();
    }

    // 静态方法,这个方法有点坑,调用该方法调用后会清除中断状态。
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    // 这个方法不会清除中断状态
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
   // 上面两个方法会调用这个本地方法,参数代表是否清除中断状态
   private native boolean isInterrupted(boolean ClearInterrupted);

中断机制

如果线程被interrupt,大概有这么几种情况。

  • 如果线程堵塞在object.wait、Thread.join和Thread.sleep,将会清除线程的中断状态,并抛出InterruptedException;

  • 如果线程堵塞在java.nio.channels.InterruptibleChannel的IO上,Channel将会被关闭,线程被置为中断状态,并抛出java.nio.channels.ClosedByInterruptException;

  • 如果线程堵塞在java.nio.channels.Selector上,线程被置为中断状态,select方法会马上返回,类似调用wakeup的效果;

  • 如果不是以上三种情况,thread.interrupt()方法仅仅是设置线程的中断状态为true。

下面代码中的t1线程将永远不会被中断。程序永远不会退出。

public class ThreadInterruptTest {
    static long i = 0;
    public static void main(String[] args) {
        System.out.println("begin");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    i++;
                    System.out.println(String.valueOf(i));
                }
            }
        });
        t1.start();
        t1.interrupt();
    }
}

java的线程中断,在线程没有阻塞的情况下,是通过标识位实现的,依赖于程序员自己检查。那么,对于阻塞的线程,JVM又是如何处理的呢?
很简单,就是设置中断状态,然后唤醒线程。让线程重新工作而已。

void os::interrupt(Thread* thread) {
  assert(Thread::current() == thread || Threads_lock->owned_by_self(),
    "possibility of dangling Thread pointer");
  //获取本地线程对象
  OSThread* osthread = thread->osthread();
  if (!osthread->interrupted()) {//判断本地线程对象是否为中断
    osthread->set_interrupted(true);//设置中断状态为true
    // More than one thread can get here with the same value of osthread,
    // resulting in multiple notifications.  We do, however, want the store
    // to interrupted() to be visible to other threads before we execute unpark().
    //这里是内存屏障,内存屏障的目的是使得interrupted状态对其他线程立即可见
    OrderAccess::fence();
    //_SleepEvent相当于Thread.sleep,表示如果线程调用了sleep方法,则通过unpark唤醒
    ParkEvent * const slp = thread->_SleepEvent ;
    if (slp != NULL) slp->unpark() ;
  }
  // For JSR166. Unpark even if interrupt status already was set
  if (thread->is_Java_thread())
    ((JavaThread*)thread)->parker()->unpark();
  //_ParkEvent用于synchronized同步块和Object.wait(),这里相当于也是通过unpark进行唤醒
  ParkEvent * ev = thread->_ParkEvent ;
  if (ev != NULL) ev->unpark() ;
}

中断的使用

中断是实现任务取消的最合理的方式。在广泛接受的编程规范,中断处理应该尽可能迅速。一般而言,我们提供的库不应该捕获中断,而是应该直接抛出中断让调用者决定。

你可能感兴趣的:(java)