1 线程中断:
java中对于中断的大部分操作无外乎以下两点:
- 设置或者清除中断标志位(对运行状态线程需要自检,堵塞状态会抛出异常)
- 抛出InterruptedException
2 设置中断
直接看源码 :对上面的两个操作说的很清晰了
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* // 抛异常 前置条件,线程处于堵塞状态,中断信号用完即消失,不会保存
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.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 {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
* // 无前置条件,只是设置了中断状态字段,线程需要自检使用。入过设置中断后,再进入堵塞,OS不会发送中断信号
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
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();
}
3 自检
isInterrupted() 和 interrupted() 方法只涉及到中断状态的查询,最多是多加一步重置中断状态,并不牵涉到InterruptedException。
interrupted()是我们清除中断的唯一方法
看源码:
/**
* Tests whether the current thread has been interrupted. The
* <i>interrupted status</i> of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if the current thread has been interrupted;
* <code>false</code> otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true); // true clean signal(cleared its interrupted)
}
/**
* Tests whether this thread has been interrupted. The <i>interrupted
* status</i> of the thread is unaffected by this method.
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if this thread has been interrupted;
* <code>false</code> otherwise.
* @see #interrupted()
* @revised 6.0
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted); //底层ClearInterrupted控制清除与否
4 使用举例
我们可以使用Thread#interrupt中断一个线程,被中断的线程所受的影响为以下两种之一:
- 若被中断前,该线程处于非阻塞状态,那么该线程的中断状态被设为true, 除此之外,不会发生任何事。
- 若被中断前,该线程处于阻塞状态(调用了wait,sleep,join等方法,那么该线程将会立即从阻塞状态中退出,并抛出一个InterruptedException异常,同时,该线程的中断状态被设为false(操作系统默认操作), 除此之外,不会发生任何事。
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()-> {
try {
Thread.sleep(7000);
System.out.println("我醒了 被中断过 = " + Thread.interrupted());
System.out.println(Thread.activeCount());
} catch (InterruptedException e) {
System.out.println(e);
e.printStackTrace();
System.out.println("我被中断醒了 = " + Thread.interrupted());
}
});
thread.setDaemon(false);
thread.start();
// 需要结合blockerLock使用
thread.interrupt();// 开始之后设置中断
System.in.read();
}
// 输出
我被中断醒了 = false
响应中断的方式举例
-
public final native void wait(long timeout) throws InterruptedException;// Obejct class 搭配Synchronized同步器使用,通过异常方式通知 java.util.concurrent.locks.LockSupport#park(java.lang.Object) // 会导致LockSupport.park 立即返回,同时Thread的中断信号被设置
5 小结
- 中断异常一般是线程被中断后,在一些block类型的方法(如wait,sleep,join)中抛出。有些像gc的安全域,安全点。(可以先设置中断标志,然后进入sleep也会立即抛出异常)
- 当一个线程因为调用wait,sleep,join方法而进入阻塞状态后,若在这时中断这个线程,则这些方法将会抛出InterruptedException异常,我们可以利用这个异常,使线程跳出阻塞状态,从而终止线程。
- 中断一个处于运行状态的线程只会将该线程的中断标志位设为true, 而并不会抛出InterruptedException异常,为了能在运行过程中感知到线程已经被中断了,我们只能通过不断地检查中断标志位来实现:
- 中断一个线程,只是传递了请求中断的消息,并不会直接阻止一个线程的运行。