JDK文档说,如果一个线程被中断,当前在InterruptibleChannel的io操作中被阻塞,则关闭该通道并抛出ClosedByInterruptException.但是,使用FileChannel时会出现不同的行为:
public class Main implements Runnable {
public static void main(String[] args) throws Exception {
Thread thread = new Thread(new Main());
thread.start();
Thread.sleep(500);
thread.interrupt();
thread.join();
}
public void run() {
try {
readFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void readFile() throws IOException {
FileInputStream in = new FileInputStream("large_file");
FileChannel channel = in.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(0x10000);
for (;;) {
buffer.clear();
// Thread.currentThread().interrupt();
int r = channel.read(buffer);
if (Thread.currentThread().isInterrupted()) {
System.out.println("thread interrupted");
if (!channel.isOpen())
System.out.println("channel closed");
}
if (r < 0)
break;
}
}
}
这里,当线程被中断时,read()调用正常返回,即使通道已经关闭.没有异常被抛出.此代码打印“thread interrupted”和“channel closed”,然后在下一次调用read()时抛出ClosedChannelException.
我不知道这种行为是否允许.据我所知,read()应该正常返回而不是关闭通道或关闭通道并抛出ClosedByInterruptException.正常返回并关闭频道似乎不对.我的应用程序的问题在于,当一个执行io的FutureTask被取消时,我在其他地方得到一个意外且看似无关的ClosedChannelException.
注意:当进入read()时线程已被中断时,将按预期抛出ClosedByInterruptException.
我已经看到使用64位服务器VM(JDK 1.6.0 u21,Windows 7)的这种行为.谁能证实这一点?
最佳答案 我记得在某处读过,但我不能在这里引用来源,FileChannel有点可以中断.一旦读/写操作从JVM传递到OS,JVM就不能真正做很多事情,因此操作将花费时间.建议是以可管理的大小块读/写,因此JVM可以在处理作业到OS之前检查线程中断状态.
我认为你的例子是对这种行为的完美证明.
编辑
我认为你描述的FileChannel行为违反了“最少惊喜”的原则,但是从某个角度按预期工作,即使你按照预期订阅了那个角度.
因为FileChannel是“有点”可中断的,并且读/写操作确实是阻塞的,所以阻塞操作确实成功并返回表示磁盘上文件状态的有效数据.如果是小文件,您甚至可以获取文件的全部内容.因为你有有效的数据,’FileChannel`类的设计者觉得你可能想要在开始解除中断之前使用它.
我认为这种行为应该是真的,非常好的文档,为此您可能会提交错误.然而,不要屏住呼吸固定.
我认为,如果线程在同一循环迭代中被中断,唯一的方法是执行您正在执行的操作并明确检查线程中断标志.