ClosedByInterruptException не выбрасывается

Документы JDK говорят, что если поток прерывается, который в настоящий момент блокируется в операции я прерывания, канал закрывается и генерируется исключение **************************. Однако при использовании 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() возвращается нормально, даже если канал закрыт. Никакое исключение не выбрасывается. Этот код печатает "прерывание потока" и "канал закрыт", а затем при следующем вызове read() он выдает исключение ClosedChannelException.

Мне интересно, допустимо ли это поведение. Поскольку я понимаю документы, read() должен либо нормально возвращаться, либо не закрывать канал, либо закрывать канал, а бросать **************************. Возвращение нормально и закрытие канала кажется неправильным. Проблема для моего приложения заключается в том, что я получаю неожиданное и, казалось бы, несвязанное исключение ClosedChannelException где-то еще, когда будет отменена программа FutureTask, которая делает io.

Примечание. Исключение ************************** будет выбрано так, как ожидалось, когда поток уже прерван при вводе read().

Я видел это поведение, используя 64-разрядную серверную VM (JDK 1.6.0 u21, Windows 7). Кто-нибудь может это подтвердить?

2 ответа

Я помню, где-то читал, но я не могу процитировать источник здесь, что FileChannel является своего рода прерывистым. После того, как операция чтения/записи перешла из JVM в ОС, JVM не может реально многое сделать, поэтому операция займет время, которое требуется. Рекомендация заключалась в том, чтобы читать/записывать в управляемые куски размера, поэтому JVM может проверять состояние прерывания потока перед обработкой задания на ОС.

Я думаю, что ваш пример - прекрасная демонстрация этого поведения.

ИЗМЕНИТЬ

Я думаю, что поведение FileChannel, которое вы описываете, нарушает принцип "наименьшего удивления", но с определенного угла работает, как и ожидалось, даже если вы подписываетесь на этот угол, по желанию.

Поскольку FileChannel является "своего рода" прерывистым, и операции чтения/записи действительно блокируются, то эта операция блокировки преуспевает и возвращает достоверные данные, которые представляют состояние файла на диске. В случае небольшого файла вы можете даже вернуть все содержимое файла. Поскольку у вас есть достоверные данные, дизайнеры класса FileChannel считают, что вы можете использовать его непосредственно перед тем, как начать разматывать прерывание.

Я думаю, что это поведение должно быть действительно, действительно хорошо документировано, и для этого вы можете отправить ошибку. Однако не задерживайте дыхание на том, что когда-либо фиксируется.

Я думаю, что единственный способ сказать, прерывается ли поток в той же итерации цикла, - это делать то, что вы делаете, и явно проверять флаг прерывания потока.


Одна из возможностей заключается в том, что программа фактически доходит до конца файла до того, как доставляется прерывание. Попробуйте изменить свою программу, чтобы подсчитать общее количество прочитанных и выводимых байтов, когда вы видите, что текущий поток был прерван.

licensed under cc by-sa 3.0 with attribution.