如何编写响应 `Thread.interrupt()` 的本地代码?

9
在Java中,所有标准的阻塞方法都可以通过调用Thread.interrupt()来中断,但如果我们有包装本地库的Java绑定,该本地库会执行自己的I/O操作呢?那么本地代码应如何钩入线程并响应对Thread.interrupt()的调用呢?
1个回答

9

示例代码

有关完整的描述,包括可运行的示例代码,请参见https://github.com/NWilson/javaInterruptHook

Thread.interrupt() 如何工作?

在 Sun 的 JRE(和 OpenJDK)中,interrupt() 能够唤醒一些低级操作,例如等待监视器(Object.wait()),并提供了一个内部挂钩来通知更高级别的代码中断。这是通过 JavaLangAccess.blockedOn() 提供的,如果您愿意使用 Sun 特定的实现细节,您的代码实际上可以直接调用它。

据我所知,只有一种公开的、记录的方法可以注册该通知,即使用 java.nio.channels.spi.AbstractSelector。这是 Selector 的部分实现,它为您完成了将 JavaLangAccess.blockedOn() 通知挂钩到选择器的 wakeup() 方法中的脏活。

如何实现所有这些

实现 AbstractSelector 以创建自己的选择器;大多数方法都不相关,只需忽略它们并放入存根以消除编译器错误。当您即将进入 JNI 阻塞方法时,请调用 AbstractSelectorbegin() 方法,然后在 JNI 调用返回时调用 end()

选择器应在其 wakeup() 实现中取消 JNI 方法。

粗略代码

(有关完整的运行示例,请参见顶部链接的 github 存储库。)

class NativeTask {
    public NativeTask() {}

    public void doTask()
            throws InterruptedException {
        NativeTaskSelector selector = new NativeTaskSelector(this);
        try {
            selector.registerStart();
            doTask0(); // native method
            if (Thread.interrupted())
                    throw new InterruptedException();
        } finally {
            selector.registerEnd();
            try { selector.close(); } catch (IOException impossible) {}
        }
    }
    /* The long-running native operation. */
    native private void doTask0();

    public void wakeupTask() { wakeupTask0(); }
    /* A way to cause the native operation to wake up. */
    native private void wakeupTask0();
}

class NativeTaskSelector extends AbstractSelector {

    protected NativeTaskSelector(NativeTask task_) {
        super(null);
        task = task_;
    }

    public void registerStart() { begin(); }
    public void registerEnd() { end(); }

    final private NativeTask task;

    @Override
    public Selector wakeup() {
        task.wakeupTask();
        return this;
    }

    @Override
    protected void implCloseSelector() throws IOException {
    }

    @Override
    protected SelectionKey register(AbstractSelectableChannel arg0, int arg1,
            Object arg2) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set<SelectionKey> keys() {
        throw new UnsupportedOperationException();
    }

    @Override
    public int select() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int select(long arg0) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int selectNow() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set<SelectionKey> selectedKeys() {
        throw new UnsupportedOperationException();
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接