exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 11.05.12 14:58
Оценка:
Есть пул потоков (newCachedThreadPool). Ему сбрасывается задание через ExecutorService.submit. В этом задании возникает exception (какой именно ИМХО не важно, но все же NPE).

Когда ExecutorService вызывает get, он получает ExecutionException. Вроде как все правильно.

Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.

Кто-то может что-нибудь сказать ?

Вот простейший пример


public class ThreadTest {

    static class ThreadClass implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            System.out.println("Inside call");
            Object o = null;
            return o.hashCode();
        }
        
    }
    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();
        Future<Integer> f = es.submit(new ThreadClass());
/*        try {
            Integer i = f.get();
        } catch (InterruptedException | ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
*/
    }

}


В таком виде печатает "Inside call" и заканчивается молча.
Декомментируем — получаем exception.
With best regards
Pavel Dvorkin
Re: exception в другом потоке.
От: RomikT Германия  
Дата: 11.05.12 15:08
Оценка: +3
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Есть пул потоков (newCachedThreadPool). Ему сбрасывается задание через ExecutorService.submit. В этом задании возникает exception (какой именно ИМХО не важно, но все же NPE).


PD>Когда ExecutorService вызывает get, он получает ExecutionException. Вроде как все правильно.


PD>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.


С точки зрения реализации — обработкой таких исключений занимается Thread.uncaughtExceptionHandler и вероятно ExecutorService устанавливает соотвтствующий handler (в сорцы не лазил).

С точки зрения логики — исключение в потоке ExecutorService это вполне нормальная ситуация, которую надо обрабатывать через методы возвращённого Future. Вы же не требуете что бы любое кинутое исключение выводилось в консоль? А то что вам не нужен результат и get можно не звать — так это неправда, вы же зачем-то таск в executor заслали, значит вам в какой-то момент времени станет важно что он уже выполнился. Тут-то вы исключение и словите, если оно произошло.
Re: exception в другом потоке.
От: PAS_Tor Германия http://passtor.blogspot.com/
Дата: 11.05.12 15:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.


А почему тогда Callable, а не Runnable? Да и можно собственно постоить своего наследника Runnable, у которого обёрнут метод run, с отловом исключений.
Follow my blog @ http://passtor.blogspot.com/
Re: exception в другом потоке.
От: StanislavK Великобритания  
Дата: 11.05.12 15:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.

PD>Кто-то может что-нибудь сказать ?
Если хотите логировать, то вам никто не запрещает — оберните call в try/catch. Не совсем понятно, что вы от джавы хотите? Логировать это в System.err? Как бы не все хотят того же.
Re[2]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 11.05.12 15:14
Оценка:
Здравствуйте, PAS_Tor, Вы писали:

PD>>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.


PAS>А почему тогда Callable, а не Runnable? Да и можно собственно постоить своего наследника Runnable, у которого обёрнут метод run, с отловом исключений.


Скорее всего в конечном счете будет именно Runnable, но пока Callable, так как на результат посмотреть хочется. Но он мне не важен — все равно ничего сделать нельзя по условиям задачи. Получилось — хорошо, нет — черт с ним. Но пока идет отладка, я хочу иметь диагностику, если там внутри call что-то не так.
With best regards
Pavel Dvorkin
Re[2]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 11.05.12 15:16
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>Если хотите логировать, то вам никто не запрещает — оберните call в try/catch.


Вопрос же не в этом. Проблемы у меня нет, как отловить эти исключения я понимаю

>Не совсем понятно, что вы от джавы хотите? Логировать это в System.err? Как бы не все хотят того же.


Вот об этом , пожалуйста, подробнее. Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?
With best regards
Pavel Dvorkin
Re[3]: exception в другом потоке.
От: PAS_Tor Германия http://passtor.blogspot.com/
Дата: 11.05.12 15:30
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вот об этом , пожалуйста, подробнее. Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?


Потому что это распараллеливание задачи и обычно все вызывают Future.get() чтоб дождаться результата выполнения всех запущенных задач. А это значит, что исключение к вам прийдёт и тут уж вы сами решите логировать, игнорить или еще что-нибудь с ним делать.
Follow my blog @ http://passtor.blogspot.com/
Re[2]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 11.05.12 15:54
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>Если хотите логировать, то вам никто не запрещает — оберните call в try/catch.


Кстати, а это как ? Вот Call Stack этого call

Thread [pool-1-thread-1] (Suspended (breakpoint at line 14 in ThreadTest$ThreadClass))
ThreadTest$ThreadClass.call() line: 14
ThreadTest$ThreadClass.call() line: 1
FutureTask$Sync.innerRun() line: not available
FutureTask<V>.run() line: not available
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: not available
ThreadPoolExecutor$Worker.run() line: not available
Thread.run() line: not available


Куда мне со своим try-catch, в FutureTask$Sync.innerRun ?
With best regards
Pavel Dvorkin
Re[4]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 11.05.12 16:01
Оценка:
Здравствуйте, PAS_Tor, Вы писали:

PAS>Потому что это распараллеливание задачи и обычно все вызывают Future.get() чтоб дождаться результата выполнения всех запущенных задач. А это значит, что исключение к вам прийдёт и тут уж вы сами решите логировать, игнорить или еще что-нибудь с ним делать.


Ну давай без Future


public class ThreadTest {

    static class ThreadClass implements Runnable{

        @Override
        public void run() {
            System.out.println("Inside call");
            Object o = null;
            int hash = o.hashCode();
            
        }
        
    }
    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();
        es.submit(new ThreadClass());
    }

}


То же самое. И не придет, естественно — некуда ему придти.
With best regards
Pavel Dvorkin
Re[5]: exception в другом потоке.
От: RomikT Германия  
Дата: 11.05.12 16:22
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, PAS_Tor, Вы писали:


PAS>>Потому что это распараллеливание задачи и обычно все вызывают Future.get() чтоб дождаться результата выполнения всех запущенных задач. А это значит, что исключение к вам прийдёт и тут уж вы сами решите логировать, игнорить или еще что-нибудь с ним делать.


PD>Ну давай без Future


Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл (я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно?

Не написать проверку Future это примерно то же самое, что написать пустой catch(Throwable t) {} и потом удивляться, почему в консоли ничего нет. Я понимаю причины вашего недомения, но всё же существующее решение продиктовано вполне объективными причинами и работает хорошо в большинстве ситуаций. Если вам по какой-то причине хочется иного поведения — можете расширить ExecutorService переопределив newTaskFor и подсунуть туда FutureTask который будет в done() писать исключения в консоль.
Re[3]: exception в другом потоке.
От: Blazkowicz Россия  
Дата: 11.05.12 16:39
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?

Если поток нигде не перехватывает исключение, то он завершается, а исключение логируется в System.err неким дефолтным хэндлером.
Executor-ы пере-используют потоки. Поэтому когда они перехватывают исключение, они его себе запоминают. Но дальше не прокидывают чтобы не убить поток.
Re[6]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 12.05.12 09:02
Оценка:
Здравствуйте, RomikT, Вы писали:

RT>Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл


Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable. Но я этого и не просил.
Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени. NPE возникает как результат страничного исключения , перехватываемого ядром ОС и портируемого в java vm. Собственно, когда уже NPE, исключения в ОС больше нет,оно обработано java vm, а дальше идет нормальное выполнение с возможным убиением потока потом.

>(я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно?


Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит.

RT>Не написать проверку Future это примерно то же самое, что написать пустой catch(Throwable t)


Нет там и не может быть никакого Future, поскольку в моем последнем примере не Callable, а Runnable.

>{} и потом удивляться, почему в консоли ничего нет. Я понимаю причины вашего недомения, но всё же существующее решение продиктовано вполне объективными причинами и работает хорошо в большинстве ситуаций. Если вам по какой-то причине хочется иного поведения — можете расширить ExecutorService переопределив newTaskFor и подсунуть туда FutureTask который будет в done() писать исключения в консоль.


М-да...
With best regards
Pavel Dvorkin
Re[4]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 12.05.12 09:08
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

PD>>Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?

B>Если поток нигде не перехватывает исключение, то он завершается, а исключение логируется в System.err неким дефолтным хэндлером.
B>Executor-ы пере-используют потоки. Поэтому когда они перехватывают исключение, они его себе запоминают. Но дальше не прокидывают чтобы не убить поток.

Для нативных (Win32) потоков, если в потоке произошло необработанное исключение, то его состояние труднопредсказуемо, поэтому его убивают. Замечу, не ядро убивает, а библиотека исполняющей системы (С++ к примеру). Ты хочешь сказать, что java vm настолько уверена в себе, что готова передать заново управление потоку, в котором было необработанное программистом исключение? Понятно, что java vm его обработала, но брать на себя обработку ЛЮБЫХ исключений и быть при этом уверенным, что поток останется в рабочем состоянии... однако...
With best regards
Pavel Dvorkin
Re[5]: exception в другом потоке.
От: Blazkowicz Россия  
Дата: 12.05.12 09:21
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Для нативных (Win32) потоков, если в потоке произошло необработанное исключение, то его состояние труднопредсказуемо, поэтому его убивают. Замечу, не ядро убивает, а библиотека исполняющей системы (С++ к примеру).

Какое это имеет отношения к Java. Сама JVM, естественно, исключение перехватывает. Ведь оно логируется в консоль, а не приводит к крашу процесса.

PD>Ты хочешь сказать, что java vm настолько уверена в себе, что готова передать заново управление потоку, в котором было необработанное программистом исключение?

Чего? Исключение было обработано в реализации Executor Service. Почему оно у тебя "необработанное"?

PD>Понятно, что java vm его обработала,

При чем здесь JVM? По твоей логике если не дай бог в блоке try...catch исключение попало в catch, то поток нужно завершать?

PD>но брать на себя обработку ЛЮБЫХ исключений и быть при этом уверенным, что поток останется в рабочем состоянии... однако...

А что с ним станется, с потоком-то???
Re[7]: exception в другом потоке.
От: RomikT Германия  
Дата: 12.05.12 09:27
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, RomikT, Вы писали:


RT>>Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл


PD>Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable.

ExecutorService.submit(Runnable) тоже возвращает Future.
PD>Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени.
Когда-нибудь он конечно квант времени выделит, просто неизвестно когда.

>>(я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно?

PD>Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит.
Eсть приложение в котором основной поток шлёт задачи в ExecutorService, но совершенно не интересуется их судьбой. В частности, ему не важно успели они выполниться или нет (вызова Future.get нет). Из этого я делаю логичный вывод что ему точно так же не может быть важно по какой причине таски не выполнились — потому что не успели или потому что исключение вылетело.
Re[8]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 12.05.12 10:44
Оценка:
Здравствуйте, RomikT, Вы писали:

PD>>Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable.

RT>ExecutorService.submit(Runnable) тоже возвращает Future.

Да, верно. Только get из него вернет null. Впрочем, да, конечно, дождались хотя бы.

PD>>Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени.

RT>Когда-нибудь он конечно квант времени выделит, просто неизвестно когда.

А какое это имеет значение ? Я же не квант ждал

PD>>Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит.

RT>Eсть приложение в котором основной поток шлёт задачи в ExecutorService, но совершенно не интересуется их судьбой. В частности, ему не важно успели они выполниться или нет (вызова Future.get нет). Из этого я делаю логичный вывод что ему точно так же не может быть важно по какой причине таски не выполнились — потому что не успели или потому что исключение вылетело.

Вот тут неверно ИМХО. У меня именно такая ситуация, но я согласен, если задача не выполнится, если, скажем, обрыв связи и т.п, но меня совсем не устраивает NPE в задаче. Это моя ошибка, я хочу о ней диагностику.
В общем, здесь ИМХО не вполне корректный дизайн. Должен быть флаг, указывающий, как вести себя ExecutorService в таких случаях. Для отладки true, в production false.
With best regards
Pavel Dvorkin
Re[9]: exception в другом потоке.
От: maxkar  
Дата: 12.05.12 12:42
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>В общем, здесь ИМХО не вполне корректный дизайн. Должен быть флаг, указывающий, как вести себя ExecutorService в таких случаях. Для отладки true, в production false.

Не должен. Это не ответственность библиотечной службы выполнения задач. Да и то, у ScheduledThreadPoolExecutor можно decorateTask переопределить и делать там, что нужно. А правильнее сделать свою реализацию ExecutorService, которая ваши Runnable оборачивает в нужные вам логгеры (или что там вы хотите) и передает в следующий ExecutorService. При отладке использовать ваш Executor, в production можно и без обертки. Хотя в последнем я смысла не вижу, если вдруг ошибка будет и в production, ее тоже стоит как-то обработать.
Re[3]: exception в другом потоке.
От: rfq  
Дата: 13.05.12 04:30
Оценка: 4 (1) :)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Куда мне со своим try-catch, в FutureTask$Sync.innerRun ?

Ничего сммешного. Создайте свой Future на основе FutureTask, переопределив run() и подавайте его на исполнение через Executor.exec(). Если хочется через ExecutorService.submit, сделайте свой ExecutorService, переопределив submit.
Re[7]: exception в другом потоке.
От: StanislavK Великобритания  
Дата: 13.05.12 20:45
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, RomikT, Вы писали:


RT>>Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл

PD>Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable. Но я этого и не просил.
PD>Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени. NPE возникает как результат страничного исключения , перехватываемого ядром ОС и портируемого в java vm. Собственно, когда уже NPE, исключения в ОС больше нет,оно обработано java vm, а дальше идет нормальное выполнение с возможным убиением потока потом.
>>(я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно?
PD>Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит.
RT>>Не написать проверку Future это примерно то же самое, что написать пустой catch(Throwable t)
PD>Нет там и не может быть никакого Future, поскольку в моем последнем примере не Callable, а Runnable.
>>{} и потом удивляться, почему в консоли ничего нет. Я понимаю причины вашего недомения, но всё же существующее решение продиктовано вполне объективными причинами и работает хорошо в большинстве ситуаций. Если вам по какой-то причине хочется иного поведения — можете расширить ExecutorService переопределив newTaskFor и подсунуть туда FutureTask который будет в done() писать исключения в консоль.
PD>М-да...

Я вот вас опять не понимаю. Вроде серьезный мужчина, а троллите.
Есть аксиома — исключение в главное потоке приложения (который main) — логится, остальные — нет. Вы хотите обсудить почему оно так? Потому, что часть приложения так падают с исключением из главноего потока. Разработчикам джавы кажется, что так оно лучше будет, если его ложить (извиняюсь за французский).
Насчет остальных потоков — если у вас есть желание, то вы всегда можете поймать и залогировать, если, конечно, код, вызывающий исключение, вызывается вашим кодом.
Да, прочитав остальные сообщения в топике, смею напомнить, что java это не C++ и исключение там — нормальное дело, даже NPE.
Вот насчет этого: "NPE возникает как результат страничного исключения" я бы послушал поподробнее. Вы это откуда взяли?
Re[8]: exception в другом потоке.
От: Pavel Dvorkin Россия  
Дата: 14.05.12 02:51
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>Я вот вас опять не понимаю. Вроде серьезный мужчина, а троллите.


Я Вас тоже. Вроде серьезная дискуссия, а Вы прибегаете к таким аргументам...

SK>Есть аксиома — исключение в главное потоке приложения (который main) — логится, остальные — нет.


Вот я и хотел узнать, почему это так ? Слово аксиома меня не убеждает — мы не в аксиоматической системе.

>Вы хотите обсудить почему оно так?


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

SK>Насчет остальных потоков — если у вас есть желание, то вы всегда можете поймать и залогировать, если, конечно, код, вызывающий исключение, вызывается вашим кодом.

SK>Да, прочитав остальные сообщения в топике, смею напомнить, что java это не C++ и исключение там — нормальное дело, даже NPE.

Отмечу, что и в С++ исключения — вполне нормальное дело и обрабатыаются практически так же.

SK>Вот насчет этого: "NPE возникает как результат страничного исключения" я бы послушал поподробнее. Вы это откуда взяли?


При обращении по null происходит обращение по нулевому адресу (null pointer exception). Такое обращение приводит к исключению в процессоре , которое называется page fault, потому что в ОС Windows адреса в интервале 0..64К-1 недоступны, то есть страничный механизм настроен так, чтобы обращения к любому из этих адресов генерировали исключение. Выяснив причину page fault (причины могут быть разные, не обязательно связанные с действиями программы, например, если просто страница вытеснена в своп — тоже будет page fault), операционная система передает исключение в прикладную программу, после чего прикладная программа (в данном случае java vm) обрабатывает это исключение процессора и генерирует свое, явовское исключение (в данном случае NPE, в другом случае, скажем, ArithmeticException), которое и передается программе для обработки.
Это стандартный механизм обработки исключений процесора в x86/x64 по крайней мере.
With best regards
Pavel Dvorkin
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.