JAVA线程中断

本文深入探讨了Java中线程中断的实现机制,包括线程中断的判断、JDK源代码分析、中断状态的处理及应用。解释了在不同阻塞情况下线程中断的行为,如wait、join、sleep等,以及在IO操作中的中断处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

中断的使用

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值