如何编写响应“Thread.interrupt()”的本机代码?
How do I write native code which responds to `Thread.interrupt()`?
在 Java 中,所有标准的阻塞方法都可以通过调用 Thread.interrupt()
来中断,但是如果我们有 Java 绑定来包装一个自己执行 [=15] 的本地库呢? =]?那么本机代码应该如何挂接到线程并响应对 Thread.interrupt()
的调用?
示例代码
有关完整的文章,包括可运行的示例代码,请参阅 https://github.com/NWilson/javaInterruptHook。
Thread.interrupt()
是如何工作的?
在 Sun 的 JRE(和 OpenJDK)中,interrupt()
能够自行唤醒一些低级操作,例如等待监视器(Object.wait()
),并提供一个内部钩子用于将中断通知给更高级别的代码。这是通过 JavaLangAccess.blockedOn()
提供的,如果您愿意使用特定于 Sun 的实现细节,实际上可以通过 sun.misc.SharedSecrets
直接由您的代码调用。
据我所知,只有一种 public 记录的注册该通知的方法,即使用 java.nio.channels.spi.AbstractSelector
。这是 Selector
的部分实现,它为您完成将 JavaLangAccess.blockedOn()
通知连接到选择器的 wakeup()
方法的脏活。
如何实现这一切
实现AbstractSelector
来制作你自己的选择器;大多数方法都不相关,所以忽略它们并放入存根以关闭编译器。当您即将进入您的 JNI 阻塞方法时,调用 AbstractSelector
begin()
方法,然后在 JNI 调用返回时调用 end()
。
选择器应取消其实现中的 JNI 方法 wakeup()
。
粗略代码
(有关完整的 运行 示例,请参阅顶部链接的 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();
}
}
在 Java 中,所有标准的阻塞方法都可以通过调用 Thread.interrupt()
来中断,但是如果我们有 Java 绑定来包装一个自己执行 [=15] 的本地库呢? =]?那么本机代码应该如何挂接到线程并响应对 Thread.interrupt()
的调用?
示例代码
有关完整的文章,包括可运行的示例代码,请参阅 https://github.com/NWilson/javaInterruptHook。
Thread.interrupt()
是如何工作的?
在 Sun 的 JRE(和 OpenJDK)中,interrupt()
能够自行唤醒一些低级操作,例如等待监视器(Object.wait()
),并提供一个内部钩子用于将中断通知给更高级别的代码。这是通过 JavaLangAccess.blockedOn()
提供的,如果您愿意使用特定于 Sun 的实现细节,实际上可以通过 sun.misc.SharedSecrets
直接由您的代码调用。
据我所知,只有一种 public 记录的注册该通知的方法,即使用 java.nio.channels.spi.AbstractSelector
。这是 Selector
的部分实现,它为您完成将 JavaLangAccess.blockedOn()
通知连接到选择器的 wakeup()
方法的脏活。
如何实现这一切
实现AbstractSelector
来制作你自己的选择器;大多数方法都不相关,所以忽略它们并放入存根以关闭编译器。当您即将进入您的 JNI 阻塞方法时,调用 AbstractSelector
begin()
方法,然后在 JNI 调用返回时调用 end()
。
选择器应取消其实现中的 JNI 方法 wakeup()
。
粗略代码
(有关完整的 运行 示例,请参阅顶部链接的 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();
}
}