ClosedByInterruptException не генерируется - PullRequest
5 голосов
/ 22 августа 2010

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

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

Примечание: ClosedByInterruptException будет генерироваться, как и ожидалось, когда поток уже прерывается при входе в read ().

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

Ответы [ 2 ]

2 голосов
/ 22 августа 2010

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

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

РЕДАКТИРОВАТЬ

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

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

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

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

0 голосов
/ 22 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...