Thread.interrupt与LockSupport

本文详细探讨了Java中Thread.interrupt()方法的作用及其与InterruptedException的关系,并对比了LockSupport与Object.wait的主要区别。

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

 

 

转载自:http://agapple.iteye.com/blog/970055
              http://www.tuicool.com/articles/MveUNzF

首先抛几个问题:
       Thread.interrupt()方法和InterruptedException异常的关系?是由interrupt触发产生了InterruptedException异常?
       Thread.interrupt()会中断线程什么状态的工作? RUNNING or BLOCKING?
       LockSupport.park()和unpark(),与object.wait()和notify()的区别?
       LockSupport.park(Object blocker)传递的blocker对象做什么用?
       LockSupport能响应Thread.interrupt()事件不?会抛出InterruptedException异常?

 

 

interrupt

 

       每个线程都有一个interrupt status标志位,用于表明当前线程是否处于中断状态。调用interrupt()仅仅是置线程的中断状态位,不会停止线程。 在Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断 "。

Thread的interrupt相关方法:

 

//置线程的中断状态
public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            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);

       注意,public static boolean interrupted()会check当前线程是否处于interrupt,并重置interrupt信息

      public void interrupt()不会中断正在执行的线程,只是将线程的标志位设置成true。但是当线程被Object.wait, Thread.join和Thread.sleep等方法阻塞时,调用线程的interrput()方法,可想而知,没有占用CPU运行的线程是不可能给自己的中断状态置位的,因此会抛出InterruptedException,同时会清除线程的中断状态,因此在catch块中捕获到这个异常时,isInterrupted()始终都为false
       为什么有InterruptedException?如果线程被阻塞,它便不能核查共享变量,也就不能停止。例如调用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,都可能永久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的。,Thread.interrupt()方法不会中断一个正在运行的线程,但是该方法可以在线程受到阻塞时抛出一个中断异常(InterruptedException),这样线程就得以提早地终结被阻塞状态。
 

LockSupport

 

       LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞原语。java锁和同步器框架的核心AQS: AbstractQueuedSynchronizer,就是通过调用 LockSupport .park()和 LockSupport .unpark()实现线程的阻塞和唤醒的。LockSupport 很类似于二元信号量(只有1个许可证可供使用),如果这个许可还没有被占用,当前线程获取许可并继续执行;如果许可已经被占用,当前线程阻塞,等待获取许可。

 

public static void main(String[] args) {
     LockSupport.park();
     System.out.println("block.");
}

       运行该代码,可以发现主线程一直处于阻塞状态。因为许可默认是被占用的,调用park()时获取不到许可,所以进入阻塞状态。
       先释放许可,再获取许可,主线程能够正常终止。LockSupport许可的获取和释放,一般来说是对应的,如果多次unpark,只有一次park也不会出现什么问题,结果是许可处于可用状态,而且LockSupport是可不重入的,如果一次unpark,多次park,当前线程也会阻塞(可以理解对某一线程许可证有且仅有一个)。

public static void main(String[] args) {
    Thread thread = Thread.currentThread();
    LockSupport.unpark(thread);//释放许可
    LockSupport.park();// 获取许可
    System.out.println(111);

    LockSupport.unpark(thread);//释放许可
    LockSupport.unpark(thread);//释放许可
    LockSupport.park();// 获取许可
    System.out.println(222);

    LockSupport.unpark(thread);//释放许可
    LockSupport.park();// 获取许可
    LockSupport.park();// 获取许可
    System.out.println(333);
}

这段代码打印出111和222,不会打印333,因为第二次调用park的时候,线程无法获取许可出现阻塞。

线程如果因为调用park而阻塞的话,能够响应中断请求(中断状态被设置成true),但是不会抛出InterruptedException。

Thread t = new Thread(()->{
    System.out.println(111);
    //等待或许许可
    LockSupport.park();
    System.out.println("thread over." + Thread.currentThread().isInterrupted());
});
t.start();

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
// 中断线程
t.interrupt();

这段代码打印出111、222、333和thread over.true。


最后解答之前的问题:
问题1: Thread.interrupt()方法和InterruptedException异常的关系?是由interrupt触发产生了InterruptedException异常?
答: Thread.interrupt()只是在Object.wait() .Object.join(), Object.sleep()几个方法会主动抛出InterruptedException异常。而在其他的的block常见,只是设置了Thread的一个标志位信息,需要程序自我进行处理。

问题2:Thread.interrupt()会中断线程什么状态的工作? RUNNING or BLOCKING?
答:Thread.interrupt设计的目的主要是用于处理线程处于block状态,比如wait(),sleep()状态就是个例子。但可以在程序设计时为支持task cancel,同样可以支持RUNNING状态。比如Object.join()和一些支持interrupt的一些nio channel设计。

问题3: LockSupport.park()和unpark(),与object.wait()和notify()的区别?
答:1.  面向的主体不一样。LockSuport主要是针对Thread进行阻塞处理,可以指定阻塞队列的目标对象,每次可以指定具体的线程唤醒。Object.wait()是以对象为纬度,阻塞当前的线程和唤醒单个(随机)或者所有线程。
       2.  实现机制不同。虽然LockSuport可以指定monitor的object对象,但和object.wait(),两者的阻塞队列并不交叉。

问题4: LockSupport.park(Object blocker)传递的blocker对象做什么用?
答: 对应的blcoker会记录在Thread的一个parkBlocker属性中,通过jstack命令可以非常方便的监控具体的阻塞对象.

问题5: LockSupport能响应Thread.interrupt()事件不?会抛出InterruptedException异常?
答:能响应interrupt事件,但不会抛出InterruptedException异常。

<think>好的,我现在需要回答用户关于Java线程中断的问题:“a线程对象.interrupt打断唤醒的是哪个线程”。首先,我要确认用户的问题核心在哪里。用户可能对interrupt()方法的作用机制不太清楚,尤其是当线程处于等待状态时,这个方法是如何生效的。 首先,我应该回顾Java中interrupt()方法的基本概念。interrupt()方法用于中断一个线程,但具体效果取决于线程的状态。如果线程正在运行,它只是设置中断标志;如果线程处于阻塞状态(如sleep、wait、join),则会抛出InterruptedException,并清除中断状态。 接下来,用户提到的“打断唤醒”可能是指当线程被阻塞时,调用interrupt()会唤醒它。比如,当线程在sleep()时,调用interrupt()会抛出异常,从而唤醒线程。这时需要明确的是,interrupt()唤醒的是被调用interrupt()的那个线程对象对应的线程,也就是a线程对象所代表的线程。 然后,我需要考虑用户可能的误区。比如,用户可能误以为调用某个线程的interrupt()会影响其他线程,或者不清楚中断标志的处理方式。需要澄清interrupt()的作用范围仅限于目标线程,不会直接影响其他线程。 还要考虑代码示例。给出一个例子,比如线程A正在sleep,主线程调用a.interrupt(),这时线程A会抛出InterruptedException,并处理中断。这样用户能更直观地理解。 另外,需要区分不同阻塞状态下的反应。比如,在Object.wait()、Thread.join()、LockSupport.park()等情况下,interrupt()的效果是否一致。同时,要强调处理InterruptedException的重要性,通常需要重新设置中断状态或者妥善处理异常,避免程序出现不可预期行为。 最后,总结关键点:interrupt()唤醒的是被调用该方法的线程对象所对应的线程,具体表现为抛出异常或设置中断标志,开发者需根据线程状态进行相应处理。</think>在Java中,通过`a线程对象.interrupt()`方法触发的中断操作,**实际唤醒/影响的是`a线程对象`对应的线程本身**。以下是关键解析: --- ### 核心机制 1. **操作对象明确性** `interrupt()`是线程实例方法,调用`a.interrupt()`时: - 直接影响对象:仅作用于`a`线程对象代表的线程 - 不会影响其他线程(包括调用此方法的当前线程) 2. **具体唤醒场景** 只有当目标线程处于以下阻塞状态时,`interrupt()`会触发**唤醒+中断异常**: | 阻塞方法 | 触发结果 | |--------------------------|----------------------------------| | `Thread.sleep()` | 抛出`InterruptedException` | | `Object.wait()` | 抛出`InterruptedException` | | `LockSupport.park()` | 直接解除阻塞(不抛异常) | | `Thread.join()` | 抛出`InterruptedException` | --- ### 验证示例 ```java public static void main(String[] args) { Thread worker = new Thread(() -> { try { Thread.sleep(5000); // 阻塞状态 } catch (InterruptedException e) { System.out.println("我被中断唤醒了!"); // 输出此语句 } }); worker.start(); worker.interrupt(); // 明确中断worker线程 } ``` --- ### 特殊场景说明 1. **非阻塞状态的线程** 若线程正在运行(未处于上述阻塞方法中),`interrupt()`仅会设置中断标志位: ```java Thread worker = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { // 持续运行... } System.out.println("检测到中断标志,退出循环"); }); worker.start(); worker.interrupt(); // 设置中断标志 ``` 2. **中断状态清除** 当通过`InterruptedException`退出阻塞时,**中断标志会被自动清除**,若需保持中断状态,需在catch块中重新标记: ```java catch (InterruptedException e) { Thread.currentThread().interrupt(); // 重新设置中断标志 } ``` --- ### 总结表 | 操作对象 | 作用目标 | 阻塞状态响应 | 非阻塞状态响应 | |------------------|---------------------|--------------------------------|-------------------------| | `a.interrupt()` | `a`对应的线程 | 抛出异常或解除阻塞 | 仅设置中断标志 | 通过理解这种明确的目标指向性,可以更精准地控制多线程的中断逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值