Thread.interrupt 快速解读

Thread.interrupt用于将线程标记为中断状态,当线程在sleep、wait、join阻塞或进行可中断I/O操作时,会抛出InterruptedException或ClosedByInterruptException。捕获这些异常后,可通过return、break或异常来结束线程。如果线程正忙于Selector选择操作,它会立即返回并设置中断状态。

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

        特性
        [Interrupt为什么有时候有用,有时候没用呢。]
  • Interrupt设置一个线程为中断状态
  • Interrupt操作的线程处于sleep,wait,join 阻塞等状态的时候,会抛出一个InterruptedException
  • Interrupt操作的线程在可中断通道上因调用某个阻塞的 I/O 操作(serverSocketChannel. accept()、socketChannel.connect、socketChannel.open、 
    socketChannel.read、socketChannel.write、fileChannel.read、fileChannel.write),会抛出一个ClosedByInterruptException
  • 我们通过try/catch捕获后则可进行return/break/throw new XXException()等方式返回来销毁或结束线程

         下面来看例子
         第一个例子解释了为什么Interrupt执行后线程依然没有中断
         后两个例子针对I/O阻塞以及sleep等状态进行了中断操作

 例子1.
/**
 * 常规interrupt
 * 
 * @author Allen
 * @date 2017年2月21日
 *
 */
public class e1 implements Runnable {
	public static void main(String[] args) {
		e1 nm=new e1();
		Thread thread = new Thread(nm);
		System.out.println("躁起来修电脑去");
		System.out.println("interrupt state = " + thread.isInterrupted());
		thread.start();
		nm.sleep(500);
		thread.interrupt();
		System.out.println("别修复了,世界末日了");
		System.out.println("interrupt state = " + thread.isInterrupted());
	}

	public void run() {
		System.out.println("开始修复电脑");
		for (int i = 10; i <= 100; i += 10) {
			if(Thread.interrupted())
				System.out.println("~~别烦我我得修完了");
			System.out.println("修复进度" + i + "%");
			sleep(200);
		}
		System.out.println("修复完毕");

	}
	/**
	 * 自己写个sleep条件循环为了禁止Interrupt对Thread.sleep(x)时的异常抛出
	 * @param step
	 * @author Allen
	 * @date 2017年2月21日
	 */
	private void sleep(int step) {
		long time = System.currentTimeMillis();
		while ((System.currentTimeMillis() - time < step)) {
		}
	}
}

执行结果
躁起来修电脑去
interrupt state = false
开始修复电脑
修复进度10%
修复进度20%
修复进度30%
别修复了,世界末日了
interrupt state = true
~~别烦我我得修完了
修复进度40%
修复进度50%
修复进度60%
修复进度70%
修复进度80%
修复进度90%
修复进度100%
修复完毕

上面可见在线程启动后我们在nw.sleep(500)后,针对启动的线程进行了thread.interrupt(),然而thread.isInterrupted()也返回了true,但是线程依然正在运行。因为我们这里的sleep是自己写的并不是用的Thread.sleep或io通道所以无法通过exception进行线程终端捕获,线程也不会抛出exception

例子2.
/**
 * interrupt try/catch销毁版
 * 
 * @author Allen
 * @date 2017年2月21日
 *
 */
public class e2 implements Runnable {
	public static void main(String[] args) throws Exception {
		e2 nm = new e2();
		Thread thread = new Thread(nm);
		System.out.println("躁起来修电脑去"); 
		System.out.println("interrupt state = " + thread.isInterrupted());
		thread.start();
		Thread.sleep(500);
		thread.interrupt();
		System.out.println("别修复了,世界末日了");
		/**
		 * 因为Thread.sleep 触发了中断状态 所以interrupted状态被清除
		 * 所以这里打印的也是false
		 */
		System.out.println("interrupt state = " + thread.isInterrupted());
	}

	public void run() {
		System.out.println("开始修复电脑");
		for (int i = 10; i <= 100; i += 10) {
			if (Thread.interrupted())
				System.out.println("~~别烦我我得修完了");
			System.out.println("修复进度" + i + "%");
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println("抛异常了被try/catch死神捕获了,只能return了");
					return;
				}
		}
		System.out.println("修复完毕");

	}

}

输出

躁起来修电脑去
interrupt state = false
开始修复电脑
修复进度10%
修复进度20%
修复进度30%
别修复了,世界末日了
interrupt state = false  //这里为什么返回false了呢?
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at TwoPhaseTerminationPattern.interrupt.e2.run(e2.java:34)
	at java.lang.Thread.run(Thread.java:724)
抛异常了被try/catch死神捕获了,只能return了

可见例子2中因为是用了Thread.sleep,我们在调用interrupt的时候成功的在目标线程中抛出了InterruptedException,从而我们可以进行一些列操作
对于interrupte state为什么在这个成功捕获的异常下居然返回false了。

我们看一下API

public boolean isInterrupted()
Tests whether this thread has been interrupted. The interrupted status of the thread is unaffected by this method.
A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by this method returning false.

Returns:
true if this thread has been interrupted; false otherwise.
See Also:
interrupted()

原来是因为当抛出exception后线程中断重置状态了所以返回false了

例子3 io阻塞下的interrupt

/**
 * interrupt i/o阻塞
 * 
 * @author Allen
 * @date 2017年2月21日
 *
 */
public class e3 implements Runnable {
	public static void main(String[] args) throws Exception {
		e3 nm = new e3();
		Thread thread = new Thread(nm);
		System.out.println("燥起来修电脑去");
		System.out.println("interrupt state = " + thread.isInterrupted());
		thread.start();
		Thread.sleep(800);
		thread.interrupt();
		System.out.println("别修复了,世界末日了");
		System.out.println("interrupt state = " + thread.isInterrupted());
	}

	public void run() {
		System.out.println("开始修复电脑");
		for (int i = 10; i <= 100; i += 10) {
			if (Thread.interrupted())
				System.out.println("~~别烦我我得修完了");
			System.out.println("修复进度" + i + "%");
			if (i == 70) {
				try {
					System.out.println("建立一个nio ServerSocketChannel我就继续修复");
					ServerSocketChannel ss = ServerSocketChannel.open();
					ss.socket().bind(new InetSocketAddress(4488));
					System.out.println("建立好了");
					while (true) {
						// 阻塞一下
						ss.accept();
					}
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println("抛异常了被try/catch死神补货了,只能return了");
					return;
				}
			}

		}
		System.out.println("修复完毕");

	}
}

输出

燥起来修电脑去
interrupt state = false
开始修复电脑
修复进度10%
修复进度20%
修复进度30%
修复进度40%
修复进度50%
修复进度60%
修复进度70%
建立一个nio ServerSocketChannel我就继续修复
建立好了
别修复了,世界末日了
interrupt state = true  //这里怎么又出现true了,捕获了exception不是应该重置状态么?
java.nio.channels.ClosedByInterruptException
	at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:248)
	at TwoPhaseTerminationPattern.interrupt.e3.run(e3.java:41)
	at java.lang.Thread.run(Thread.java:724)
抛异常了被try/catch死神补货了,只能return了

为什么io例子中interrupt的状态又成了true?
又翻了翻API

public void interrupt()
Interrupts this thread.
Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Interrupting a thread that is not alive need not have any effect.

Throws:
SecurityException - if the current thread cannot modify this thread


没关系还有中文的jdk7

public void interrupt()
中断线程。
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException。

如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException。

如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

如果以前的条件都没有保存,则该线程的中断状态将被设置。

中断一个不处于活动状态的线程不需要任何作用。

抛出:
SecurityException - 如果当前线程无法修改该线程

可以看到当wait,join.sleep因interrupt而抛出InterruptedExcetion前,还会清除/重置其中断状态为false,所以例子2中显示为false
然而IO操作中,仅仅是抛出一个ClosedByInterruptException 所以interrupted显示true



就到这里了,相信大家对interrupt的用法已经有一定了解了。微笑



@RabbitListener(queues = Config.ITEM_QUEUE) @Transactional(rollbackFor = Exception.class) public void systemListener(String content, Message message) { try { Thread.sleep(3000); } catch (InterruptedException err) { Thread.currentThread().interrupt(); log.error("err:f]", err); } catch (Exception err) { log.error("err:f]", err); } String topic = message.getMessageProperties().getReceivedRoutingKey(); log.info("systemQueue.: " + content + "topic::" + topic); try { log.info("********************************审批结果处理start:content:[{}]************************", content); JSONObject jsonObject = JSON.parseObject(content); ApprovalParamEntity approvalParam = JSON.parseObject(content, ApprovalParamEntity.class); if (approvalParam.getCode() == null || StringUtils.isEmpty(MqTypeEnum.getMsgByCode(approvalParam.getCode()))) { log.error("没有找到code信息{}", jsonObject); return; } // 发起审批消息和审批转办消息 暂不处理 if (MqStatusEnum.START.getCode().equals(approvalParam.getActionCode()) || MqStatusEnum.TRANSFER.getCode().equals(approvalParam.getActionCode())) { return; } BTContextHolder.beginIgnoreTenant(); ConsumeFlowMessage medalService = factory.getDealService(approvalParam.getCode()); if (medalService != null) { medalService.dealBusinessByApproveResult(approvalParam); } log.info("********************************审批结果处理end:content:[{}]************************", content); } catch (Exception e) { log.error("********************【审批异常!】********************,错误信息为:{}", e); } finally { BTContextHolder.resetTenant(); } }解读代码
06-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值