Почему я должен обернуть каждый вызов Thread.sleep() в оператор try/catch?

Я пытаюсь написать свою первую многопоточную программу на Java. Я не могу понять, почему мы требуем обработки исключений вокруг циклов for. Когда я компилирую без предложений try/catch, это дает исключение InterruptedException. (Вот сообщение:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
Unhandled exception type InterruptedException

)

Но при запуске с try/catch sysout в блоках catch никогда не отображается - это означает, что в любом случае такое исключение не было обнаружено!

public class SecondThread implements Runnable{
    Thread t;

    SecondThread(){
        t = new Thread(this, "Thread 2");
        t.start();
    }

    public void run(){
        try{
            for(int i=5 ; i>0 ; i--){
                System.out.println("thread 2: " + i);
                Thread.sleep(1000);
            }
        }
        catch(InterruptedException e){
            System.out.println("thread 2 interrupted");
        }
    }
}


public class MainThread{

    public static void main(String[] args){
        new SecondThread();

        try{
            for(int i=5 ; i>0 ; i--){
                System.out.println("main thread: " + i);
                Thread.sleep(2000);
            }
        }
        catch(InterruptedException e){
            System.out.println("main thread interrupted");
        }
    }
}

4 ответа

Метод Thread.sleep генерирует InterruptedException, если он обнаруживает, что в текущем потоке установлен флаг прерывания, рано выходит из спящего режима и позволяет использовать исключение для перемещения элемента управления где-либо за пределами текущего потока. Этот флаг устанавливается, только если что-то вызывает прерывание в потоке.

Поскольку ваша программа не вызывает прерывание ни в одном из потоков, InterruptedException не будет выброшено при запуске этой программы. Компилятор по-прежнему требует, чтобы вы перехватили исключение, поскольку это проверенное исключение, объявленное в методе sleep.

Если вы добавите такой метод в SecondThread

public void cancel() {
    t.interrupt();
}

затем вызовите метод отмены в основном методе, например так:

public static void main(String[] args){
    SecondThread secondThread =  new SecondThread();

    try{
        for(int i=5 ; i>0 ; i--){
            System.out.println("main thread: " + i);
            Thread.sleep(2000);
            secondThread.cancel();
        }
    }
    catch(InterruptedException e){
        System.out.println("main thread interrupted");
    }
}

вы увидите println, где InterruptedException пойман в методе выполнения SecondThread.

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

Вы должны справиться InterruptedException в ваших темах, потому что вы вызываете методы, которые бросают InterruptedExceptionи Java спроектирован таким образом, что вы всегда должны обрабатывать проверенные исключения. То есть "в теме" не имеет значения.

Как сказано в JLS Sec 11.2:

Язык программирования Java требует, чтобы программа содержала обработчики для проверенных исключений, которые могут возникнуть в результате выполнения метода или конструктора (§8.4.6, §8.8.5).

Эти обработчики могут быть в форме try/catch (InterruptedException), или же throws InterruptedException; тем не менее, вы не можете использовать последний, потому что метод подписи void run() не позволяет добавить проверенное исключение.

Таким образом, вы должны использовать try/catch.

Когда я компилирую без предложений try/catch, это дает исключение InterruptedException.

Исключения генерируются во время выполнения, а не во время компиляции, поэтому это не может быть правдой!

Возможно, вы получили ошибку компиляции Thread.sleep может бросить InterruptedException, но SecondThread.runиз которого Thread.sleep называется, не объявляет, что может его кинуть. Поэтому компилятор не работает, потому что исключение не может никуда идти.

Обычно есть два способа решить это:

  • поймать исключение или
  • добавить throws пункт к вашему методу.

Последнее невозможно в этом случае, потому что SecondThread.run переопределяет из Runnable.run, который не объявляет, что выбрасывает какие-либо исключения. Так что вам нужно поймать исключение.

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

InterruptedException является проверенным исключением и должно быть перехвачено. В вашем коде он кидается sleep-методом. Поэтому, если вы не закроете его или не перезапустите, компилятор остановится, так как это проверенное исключение.

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

Так что это на самом деле нужно ловить, и у него есть действительное использование.

Другие вопросы по тегам