你的位置:首页 > 软件开发 > Java > Java 线程的中断机制

Java 线程的中断机制

发布时间:2017-12-09 05:00:10
今天我们聊聊 Java 线程的中断机制。线程中断机制提供了一种方法,用于将线程从阻塞等待中唤醒,并作出相应的“受控中断”处理。synchronized (lock) { try { while (!check()) { lock.wait(1000); } } catch ...

今天我们聊聊 Java 线程的中断机制。

线程中断机制提供了一种方法,用于将线程从阻塞等待中唤醒,并作出相应的“受控中断”处理。

synchronized (lock) { try {  while (!check()) {   lock.wait(1000);  } } catch (InterruptedException e) {  e.printStackTrace(); }}

这段代码使用了 Java 提供的 wait/notify 机制,线程执行 lock.wait() 会阻塞,有三种情况使线程恢复运行。

  1. 超时 1000ms 结束,正常执行下一句代码。

  2. 另一个线程执行下述代码主动唤醒

    synchronized (lock) { lock.notifyAll(); // or lock.notify();}

    这也会正常执行下一句代码。

  3. 另一个线程要求等待的线程“中断”

    // 拿到等待中的线程的引用Thread a;a.interrupt();

    被“中断”的线程 a,会在 lock.wait() 处抛出 InterruptedException 异常。

综上所述,你可以认为 object.wait() 内部在做这些事:

boolean checkTimeout = timeout > 0;Thread current = Thread.currentThread();lock.addWaiter(current);while (!current.isNotified()) { if (current.isInterrupted()) {  current.clearInterrupted();  throw new InterruptedException(); } if (checkTimeout) {  if (timeout == 0) break;  timeout--; }}

这不完全准确,因为 wait 不使用这种“忙轮询”的方式做检查,但关于标志位的判断逻辑是正确的。

让我们从手动中断开始探究,

// sun.nio.ch.Interruptiblepublic interface Interruptible { void interrupt(Thread var1);}// java.lang.Threadprivate volatile Interruptible blocker;private final Object blockerLock = new Object();public void interrupt() { if (this != Thread.currentThread())  checkAccess(); synchronized (blockerLock) {  Interruptible b = blocker;  if (b != null) {   interrupt0();   b.interrupt(this);   return;  } } interrupt0();}// Just to set the interrupt flagprivate native void interrupt0();

能够看出, thread.interrupt() 先判断权限,然后实际调用 interrupt0() 设置线程的中断标志,如果当前线程有 nio 的 Interruptible 那么还会回调它。

注意,interrupt0() 只是设置了线程的中断标志。

一个线程怎么知道自己被打断了?

// java.lang.Threadpublic static boolean interrupted() { return currentThread().isInterrupted(true);}public boolean isInterrupted() { return isInterrupted(false);}private native boolean isInterrupted(boolean clearInterrupted);

也就是说, isInterrupted(boolean) 会返回线程是否被打断,并根据需要清空中断标志。

我们发现,当一个线程并不阻塞,没有在 object.wait() , thread.join() , Thread.sleep()等不受 Java 程序逻辑控制的区域时,那么线程是否被打断只能通过检查中断标志得知。

当一个函数调用可能阻塞,Java 会在阻塞的源头签名里标记 throws InterruptedException ,并要求编写 try catch 处理中断。

当线程阻塞,就像上文所述,Java 检查到中断标志,先将其清除,然后抛出 InterruptedException 。

// java.lang.Objectpublic final void wait() throws InterruptedException { wait(0);}public final native void wait(long timeout) throws InterruptedException;

如果一个线程收到 InterruptedException ,之后仍然执行了会引发阻塞的代码,它将像“没事人”一样继续阻塞住。因为 Java 在内部将中断标志清除了!

我们常见地编写以下三类处理 InterruptedException 的代码:

将 InterruptedException 交由上层处理。

public void foo() throws InterruptedException { synchronized (lock) {  lock.wait(); }}

遇到 InterruptedException 重设中断标志位。

try { synchronized (lock) {   lock.wait();  } } catch (InterruptedException e) {  Thread.currentThread().interrupt(); //break; }

先忙完,再重新抛出 InterruptedException 。

public void bar() throws InterruptedException { InterruptedException ie = null; boolean done = false; while (!done) {  synchronized (lock) {   try {    lock.wait();   } catch (InterruptedException e) {    ie = e;    continue;   }  }  done = true; } if (ie != null) {  throw ie; }}

如果一个线程无视中断标志和 InterruptedException ,它仍然能够跑的很好。但 这与我们设计多线程的初衷是违背的 ,我们希望线程之间是和谐的有序协作以实现特定功能,因此 受控线程应当对中断作出响应 。而 Java 留给开发者这一自由,我们应当予以善用。如果你想学习java可以加我的学习群669823128

 

原标题:Java 线程的中断机制

关键词:JAVA

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。