“Java中断及中断响应”的版本间差异

来自Wikioe
跳到导航 跳到搜索
 
第61行: 第61行:


== 中断响应 ==
== 中断响应 ==
Java 中,使用“interrupt()”方法请求中断,并不会改变线程运行状态,只是改变了线程中断信号。
Java 中,使用“interrupt()”方法请求中断,并不会改变线程运行状态,只是改变了线程中断信号。<br/>
响应中断的两种方式:
中断处理的两种方式:
# 对于不响应中断的方法,需要在
# 对于不响应中断的方法,需要通过代码方法轮询中断状态,看看它是否被请求停止正在做的事情;
# 响应中断的方法,会抛出'''InterruptedException'''异常(并重置中断标识),处理该异常即可;
#: “isInterrupted”:获取中断标识;
 
#: “interrupted”获取并清楚中断标识;
 
# 响应中断的方法,会'''抛出InterruptedException异常(并重置中断标识)''',处理该异常即可;
当线程处在不同的状态下(Running,Blocked,Waiting),响应中断信号的方式不一样:
# 非阻塞:在需要处理中断逻辑的地方,利用“interrupted”或“isInterrupted”方法判断中断标示,并编写处理代码,以响应处理中断;
# 阻塞:JVM会让线程马上'''抛出异常(InterruptedException)并把中断状态置回为false''',从而让线程可以选择是否响应中断;


=== 响应中断的方法 ===
* 可从源码注释中看出,方法是否响应中断;
<pre>
<pre>
     /*
     /*
第87行: 第86行:
</pre>
</pre>


=== 响应中断的方法 ===
# 若方法使线程进入'''可取消的阻塞状态'''、'''等待'''或是'''超时等待'''的状态,则会响应中断;
# 响应中断的方法: 线程进入'''等待或是超时等待'''的状态后,调用interrupt方法都是会响应中断的;
#: 如:“Object.wait”、“Thread.join”、“Thread.sleep”、“LockSupport.park”等方法。
#: 所以响应中断的方法:Object.wait()、Thread.join、Thread.sleep、LockSupport.park等方法。
# 对于'''不可取消的阻塞状态''',(如:获取锁操作是不能被中断的,要一直阻塞等到到它获取到锁为止),则该方法不会响应中断;
# 不响应中断的方法:线程进入'''阻塞状态'''后,以及阻塞在'''ReentrantLock.lock方法'''里面的线程,是不响应中断的。
#: 如:“synchronized”的方法或是代码块,“ReentrantLock.lock”方法。
#: 等待进入synchronized的方法或是代码块,都是会被阻塞的,此时不会响应中断;
#: 可以使用“ReentrantLock.lockInterruptibly”方法响应中断(ReentrantLock底层是使用LockSupport.park方法进行等待的);
#: 可以使用“ReentrantLock.lockInterruptibly”方法响应中断;
#: 也可以使用超时锁“Lock.tryLock(timeout,unit)”,在超时后会抛出异常;


=== InterruptedException 处理 ===
=== InterruptedException 处理 ===
第100行: 第99行:


对于 '''InterruptedException''':
对于 '''InterruptedException''':
# 最糟糕的处理方式是 “生吞(swallow)”:即,捕捉它,然后什么也不做(或者记录下它)。
*(最糟糕的方式是 “生吞(swallow)”:即,捕捉它,然后什么也不做)。
#
# 通常最容易的策略是直接抛出 InterruptedException(需要方法“throws InterruptedException”):
#: <syntaxhighlight lang="java">
    try {
        sleep(delay);
    } catch (InterruptedException e) {
        throw e;
    }
</syntaxhighlight>
# 在catch子句中调用'''Thread.currentThread.interrupt()'''来重设中断状态位(因为抛出中断异常后,中断状态位会被清除,即false)
#: <syntaxhighlight lang="java">
    try {
        sleep(delay);
    } catch (InterruptedException e) {
        Thread.currentThread().isInterrupted();
    }
</syntaxhighlight>

2020年10月19日 (一) 23:34的最新版本


中断机制

Java的中断为协作机制,即 A 不能直接中断 B,而是调用 “B.interrupt()” 来申请中断 B (设置中断状态);然后由 B 通过 “interrupted()”(会重置中断状态)或 “isInterrupted()”(不会重置中断状态)读取中断状态,并决定如何响应。

中断相关源码

	private volatile Interruptible blocker;				// 
    private final Object blockerLock = new Object();	// 用于synchronized锁定,实现同步安全
	
	/* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
     */
	void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
	
	...
	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);		// 调用Interruptible对象b 的同步方法
                return;
            }
        }
        interrupt0();
    }
	
	public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
	
	public boolean isInterrupted() {
        return isInterrupted(false);
    }
	
	private native boolean isInterrupted(boolean ClearInterrupted);
	...
	private native void interrupt0();

其中:

  1. “interrupt()” 方法只是调用了“blocker.interrupt()”和“interrupt0()”,并不对线程运行产生影响;
  2. “blocker”域用于 nio 的中断?【???待查证】
  3. “interrupt0()” 是一个 native方法,仅用于设置中断标识(其他的);
  4. “interrupted()”(静态方法)和“isInterrupted()”(实例方法)最终都是调用本地方法“isInterrupted”;
  5. “isInterrupted”是一个 native方法,用于判断中断标识,并根据参数决定是否重置中断状态;
  • 中断标识的使用,都是在native方法中。

请求中断

Java的中断:

  1. 没有可以强制线程终止的方法。
  2. interrupt 方法用于请求终止线程

中断响应

Java 中,使用“interrupt()”方法请求中断,并不会改变线程运行状态,只是改变了线程中断信号。
中断处理的两种方式:

  1. 对于不响应中断的方法,需要通过代码方法轮询中断状态,看看它是否被请求停止正在做的事情;
    “isInterrupted”:获取中断标识;
    “interrupted”获取并清楚中断标识;
  2. 响应中断的方法,会抛出InterruptedException异常(并重置中断标识),处理该异常即可;

响应中断的方法

  • 可从源码注释中看出,方法是否响应中断;
     /*
     * ...
     *
     * <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}.
     *
     * ...
     */
  1. 若方法使线程进入可取消的阻塞状态等待或是超时等待的状态,则会响应中断;
    如:“Object.wait”、“Thread.join”、“Thread.sleep”、“LockSupport.park”等方法。
  2. 对于不可取消的阻塞状态,(如:获取锁操作是不能被中断的,要一直阻塞等到到它获取到锁为止),则该方法不会响应中断;
    如:“synchronized”的方法或是代码块,“ReentrantLock.lock”方法。
    可以使用“ReentrantLock.lockInterruptibly”方法响应中断(ReentrantLock底层是使用LockSupport.park方法进行等待的);
    也可以使用超时锁“Lock.tryLock(timeout,unit)”,在超时后会抛出异常;

InterruptedException 处理

如果抛出 InterruptedException 意味着一个方法是阻塞方法,那么调用一个阻塞方法则意味着您的方法也是一个阻塞方法,而且您应该有某种策略来处理 InterruptedException。

对于 InterruptedException

  • (最糟糕的方式是 “生吞(swallow)”:即,捕捉它,然后什么也不做)。
  1. 通常最容易的策略是直接抛出 InterruptedException(需要方法“throws InterruptedException”):
        try {
            sleep(delay);
        } catch (InterruptedException e) {
            throw e;
        }
    
  2. 在catch子句中调用Thread.currentThread.interrupt()来重设中断状态位(因为抛出中断异常后,中断状态位会被清除,即false)
        try {
            sleep(delay);
        } catch (InterruptedException e) {
            Thread.currentThread().isInterrupted();
        }