Здравствуйте, 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 заслали, значит вам в какой-то момент времени станет важно что он уже выполнился. Тут-то вы исключение и словите, если оно произошло.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Куда мне со своим try-catch, в FutureTask$Sync.innerRun ?
Ничего сммешного. Создайте свой Future на основе FutureTask, переопределив run() и подавайте его на исполнение через Executor.exec(). Если хочется через ExecutorService.submit, сделайте свой ExecutorService, переопределив submit.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?
Если поток нигде не перехватывает исключение, то он завершается, а исключение логируется в System.err неким дефолтным хэндлером.
Executor-ы пере-используют потоки. Поэтому когда они перехватывают исключение, они его себе запоминают. Но дальше не прокидывают чтобы не убить поток.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, StanislavK, Вы писали:
SK>>Я вот вас опять не понимаю. Вроде серьезный мужчина, а троллите. PD>Я Вас тоже. Вроде серьезная дискуссия, а Вы прибегаете к таким аргументам...
это и не аргумет вовсе.
SK>>Вот насчет этого: "NPE возникает как результат страничного исключения" я бы послушал поподробнее. Вы это откуда взяли? PD>При обращении по null происходит обращение по нулевому адресу (null pointer exception). Такое обращение приводит к исключению в процессоре , которое называется page fault, потому что в ОС Windows адреса в интервале 0..64К-1 недоступны, то есть страничный механизм настроен так, чтобы обращения к любому из этих адресов генерировали исключение. Выяснив причину page fault (причины могут быть разные, не обязательно связанные с действиями программы, например, если просто страница вытеснена в своп — тоже будет page fault), операционная система передает исключение в прикладную программу, после чего прикладная программа (в данном случае java vm) обрабатывает это исключение процессора и генерирует свое, явовское исключение (в данном случае NPE, в другом случае, скажем, ArithmeticException), которое и передается программе для обработки. PD>Это стандартный механизм обработки исключений процесора в x86/x64 по крайней мере.
Откуда вы все это взяли? Точнее откуда взяли понятно, но кто вам сказал, что ява так работает? Если в яве машине возникнет обращение по несуществующему адресу или деления на ноль, то процесс упадет, в лучшем случае, скинув дамп и немного диагностики. После такого никто в своем уме не будет пытаться восстановиться. А выглядеть это будет вот так (или так):
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c911010, pid=3244, tid=280
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_02-b09 mixed mode, sharing)
# Problematic frame:
# C [ntdll.dll+0x1010]
#
# An error report file with more information is saved as hs_err_pid3244.log
#
# If you would like to submit a bug report, please visit:
# HotSpot Virtual Machine Error Reporting Page
чтобы не быть голословным, вот например, код операции, которая возвращает размер массива(из openjdk):
Видите CHECK_NULL после того как ссылку забрали со стека?
Еще стоит посмотреть, на месте в коде jdk где используется, виндовый SEH. Он как раз и отлавливает те самые исключения о которых вы говорите — EXCEPTION_ACCESS_VIOLATION, EXCEPTION_INT_DIVIDE_BY_ZERO и т.д. В этом коде и следа нет прокидывания этих исключений дальше.
Здравствуйте, StanislavK, Вы писали:
SK>Есть аксиома — исключение в главное потоке приложения (который main) — логится, остальные — нет.
Вы ошибаетесь:
public class Test{
public static void main(String[] arg){
new Thread(){
public void run(){
throw new RuntimeException();
}
}.start();
}
}
Exception in thread "Thread-0" java.lang.RuntimeException
at Test$1.run(Test.java:5)
Дело совершенно не в main потоке, а в реализации ExecutorService
Есть пул потоков (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.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.
А почему тогда Callable, а не Runnable? Да и можно собственно постоить своего наследника Runnable, у которого обёрнут метод run, с отловом исключений.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал. PD>Кто-то может что-нибудь сказать ?
Если хотите логировать, то вам никто не запрещает — оберните call в try/catch. Не совсем понятно, что вы от джавы хотите? Логировать это в System.err? Как бы не все хотят того же.
Здравствуйте, PAS_Tor, Вы писали:
PD>>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE. То есть в потоке он произошел и ... ничего. Никакого stack trace в окне Console Eclipse, совершенно ничего. Не вызови я get (а я в дальнейшем хочу его и не вызывать, так как результат мне, вообще-то, не нужен) — я бы так ничего и не узнал.
PAS>А почему тогда Callable, а не Runnable? Да и можно собственно постоить своего наследника Runnable, у которого обёрнут метод run, с отловом исключений.
Скорее всего в конечном счете будет именно Runnable, но пока Callable, так как на результат посмотреть хочется. Но он мне не важен — все равно ничего сделать нельзя по условиям задачи. Получилось — хорошо, нет — черт с ним. Но пока идет отладка, я хочу иметь диагностику, если там внутри call что-то не так.
Здравствуйте, StanislavK, Вы писали:
SK>Если хотите логировать, то вам никто не запрещает — оберните call в try/catch.
Вопрос же не в этом. Проблемы у меня нет, как отловить эти исключения я понимаю
>Не совсем понятно, что вы от джавы хотите? Логировать это в System.err? Как бы не все хотят того же.
Вот об этом , пожалуйста, подробнее. Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вот об этом , пожалуйста, подробнее. Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ?
Потому что это распараллеливание задачи и обычно все вызывают Future.get() чтоб дождаться результата выполнения всех запущенных задач. А это значит, что исключение к вам прийдёт и тут уж вы сами решите логировать, игнорить или еще что-нибудь с ним делать.
Здравствуйте, 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 ?
Здравствуйте, 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());
}
}
То же самое. И не придет, естественно — некуда ему придти.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, PAS_Tor, Вы писали:
PAS>>Потому что это распараллеливание задачи и обычно все вызывают Future.get() чтоб дождаться результата выполнения всех запущенных задач. А это значит, что исключение к вам прийдёт и тут уж вы сами решите логировать, игнорить или еще что-нибудь с ним делать.
PD>Ну давай без Future
Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл (я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно?
Не написать проверку Future это примерно то же самое, что написать пустой catch(Throwable t) {} и потом удивляться, почему в консоли ничего нет. Я понимаю причины вашего недомения, но всё же существующее решение продиктовано вполне объективными причинами и работает хорошо в большинстве ситуаций. Если вам по какой-то причине хочется иного поведения — можете расширить ExecutorService переопределив newTaskFor и подсунуть туда FutureTask который будет в done() писать исключения в консоль.
Здравствуйте, RomikT, Вы писали:
RT>Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл
Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable. Но я этого и не просил.
Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени. NPE возникает как результат страничного исключения , перехватываемого ядром ОС и портируемого в java vm. Собственно, когда уже NPE, исключения в ОС больше нет,оно обработано java vm, а дальше идет нормальное выполнение с возможным убиением потока потом.
>(я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно?
Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит.
RT>Не написать проверку Future это примерно то же самое, что написать пустой catch(Throwable t)
Нет там и не может быть никакого Future, поскольку в моем последнем примере не Callable, а Runnable.
>{} и потом удивляться, почему в консоли ничего нет. Я понимаю причины вашего недомения, но всё же существующее решение продиктовано вполне объективными причинами и работает хорошо в большинстве ситуаций. Если вам по какой-то причине хочется иного поведения — можете расширить ExecutorService переопределив newTaskFor и подсунуть туда FutureTask который будет в done() писать исключения в консоль.
Здравствуйте, Blazkowicz, Вы писали:
PD>>Почему все хотят (уж не знаю, хотят или нет, но по умолчанию делается) логгирование в основном потоке и почему нет — в потоке пула ? B>Если поток нигде не перехватывает исключение, то он завершается, а исключение логируется в System.err неким дефолтным хэндлером. B>Executor-ы пере-используют потоки. Поэтому когда они перехватывают исключение, они его себе запоминают. Но дальше не прокидывают чтобы не убить поток.
Для нативных (Win32) потоков, если в потоке произошло необработанное исключение, то его состояние труднопредсказуемо, поэтому его убивают. Замечу, не ядро убивает, а библиотека исполняющей системы (С++ к примеру). Ты хочешь сказать, что java vm настолько уверена в себе, что готова передать заново управление потоку, в котором было необработанное программистом исключение? Понятно, что java vm его обработала, но брать на себя обработку ЛЮБЫХ исключений и быть при этом уверенным, что поток останется в рабочем состоянии... однако...
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Для нативных (Win32) потоков, если в потоке произошло необработанное исключение, то его состояние труднопредсказуемо, поэтому его убивают. Замечу, не ядро убивает, а библиотека исполняющей системы (С++ к примеру).
Какое это имеет отношения к Java. Сама JVM, естественно, исключение перехватывает. Ведь оно логируется в консоль, а не приводит к крашу процесса.
PD>Ты хочешь сказать, что java vm настолько уверена в себе, что готова передать заново управление потоку, в котором было необработанное программистом исключение?
Чего? Исключение было обработано в реализации Executor Service. Почему оно у тебя "необработанное"?
PD>Понятно, что java vm его обработала,
При чем здесь JVM? По твоей логике если не дай бог в блоке try...catch исключение попало в catch, то поток нужно завершать?
PD>но брать на себя обработку ЛЮБЫХ исключений и быть при этом уверенным, что поток останется в рабочем состоянии... однако...
А что с ним станется, с потоком-то???
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, RomikT, Вы писали:
RT>>Без Future приложение никак не сможет узнать, что произошло — выкинулось NPE или планировщик решил что с потока хватит и просто не даёт ему квант времени что бы этот NPE произошёл
PD>Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable.
ExecutorService.submit(Runnable) тоже возвращает Future. PD>Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени.
Когда-нибудь он конечно квант времени выделит, просто неизвестно когда.
>>(я слегка утрирую, при большом желании по косвенным признакам узнать можно). А раз самому приложению на это наплевать, то почему вам не всё равно? PD>Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит.
Eсть приложение в котором основной поток шлёт задачи в ExecutorService, но совершенно не интересуется их судьбой. В частности, ему не важно успели они выполниться или нет (вызова Future.get нет). Из этого я делаю логичный вывод что ему точно так же не может быть важно по какой причине таски не выполнились — потому что не успели или потому что исключение вылетело.
Здравствуйте, RomikT, Вы писали:
PD>>Во-первых, ни о каком приложении речь идти не может, а только о запускающем потоке. Он, точно, не сможет узнать для случая с Runnable. RT>ExecutorService.submit(Runnable) тоже возвращает Future.
Да, верно. Только get из него вернет null. Впрочем, да, конечно, дождались хотя бы.
PD>>Во-вторых, планировщик никак не может решить, что с потока хватит и не давать ему больше времени. RT>Когда-нибудь он конечно квант времени выделит, просто неизвестно когда.
А какое это имеет значение ? Я же не квант ждал
PD>>Думал над этой фразой и пытался понять, но так и не смог. Судя по всему, есть некое самозародившееся приложение, которому на это наплевать, а есть я, который при сем присутсвует, и на это все смотрит. RT>Eсть приложение в котором основной поток шлёт задачи в ExecutorService, но совершенно не интересуется их судьбой. В частности, ему не важно успели они выполниться или нет (вызова Future.get нет). Из этого я делаю логичный вывод что ему точно так же не может быть важно по какой причине таски не выполнились — потому что не успели или потому что исключение вылетело.
Вот тут неверно ИМХО. У меня именно такая ситуация, но я согласен, если задача не выполнится, если, скажем, обрыв связи и т.п, но меня совсем не устраивает NPE в задаче. Это моя ошибка, я хочу о ней диагностику.
В общем, здесь ИМХО не вполне корректный дизайн. Должен быть флаг, указывающий, как вести себя ExecutorService в таких случаях. Для отладки true, в production false.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В общем, здесь ИМХО не вполне корректный дизайн. Должен быть флаг, указывающий, как вести себя ExecutorService в таких случаях. Для отладки true, в production false.
Не должен. Это не ответственность библиотечной службы выполнения задач. Да и то, у ScheduledThreadPoolExecutor можно decorateTask переопределить и делать там, что нужно. А правильнее сделать свою реализацию ExecutorService, которая ваши Runnable оборачивает в нужные вам логгеры (или что там вы хотите) и передает в следующий ExecutorService. При отладке использовать ваш Executor, в production можно и без обертки. Хотя в последнем я смысла не вижу, если вдруг ошибка будет и в production, ее тоже стоит как-то обработать.
Здравствуйте, 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 возникает как результат страничного исключения" я бы послушал поподробнее. Вы это откуда взяли?
Здравствуйте, 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 по крайней мере.
PD>При обращении по null происходит обращение по нулевому адресу (null pointer exception). Такое обращение приводит к исключению в процессоре , которое называется page fault, потому что в ОС Windows адреса в интервале 0..64К-1 недоступны, то есть страничный механизм настроен так, чтобы обращения к любому из этих адресов генерировали исключение. Выяснив причину page fault (причины могут быть разные, не обязательно связанные с действиями программы, например, если просто страница вытеснена в своп — тоже будет page fault), операционная система передает исключение в прикладную программу, после чего прикладная программа (в данном случае java vm) обрабатывает это исключение процессора и генерирует свое, явовское исключение (в данном случае NPE, в другом случае, скажем, ArithmeticException), которое и передается программе для обработки. PD>Это стандартный механизм обработки исключений процесора в x86/x64 по крайней мере.
Утверждать не стану, но у меня есть серьезнейшие сомнения в том, что джава завязывается на системный механизм обработки исключений, и вообще каким-либо образом с ним связана. Насколько я понимаю, все это реализуется в рантайме, а не на системном уровне. А если вылетит процессорное исключение, то джава с грохотом навернется, ибо это будет баг уже самой машины.
Кто более серьезно копал вопрос, поясните.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Eugeny__, Вы писали:
E__>Утверждать не стану, но у меня есть серьезнейшие сомнения в том, что джава завязывается на системный механизм обработки исключений, и вообще каким-либо образом с ним связана. Насколько я понимаю, все это реализуется в рантайме, а не на системном уровне. А если вылетит процессорное исключение, то джава с грохотом навернется, ибо это будет баг уже самой машины.
Рантайм java есть просто процесс Win32, который работает как обычное Win32 приложение (других не бывает). Написан на С++. Он и перехватывает исключения процессора, а поэтому java vm не падает, так же как не падает моя программа, если в ней я буду обрабатывать исключения.
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, StanislavK, Вы писали:
SK>>Есть аксиома — исключение в главное потоке приложения (который main) — логится, остальные — нет. B>Вы ошибаетесь:
Правда, ошибаюсь.
B>Дело совершенно не в main потоке, а в реализации ExecutorService
+1
SK>Откуда вы все это взяли? Точнее откуда взяли понятно, но кто вам сказал, что ява так работает? Если в яве машине возникнет обращение по несуществующему адресу или деления на ноль, то процесс упадет, в лучшем случае, скинув дамп и немного диагностики. После такого никто в своем уме не будет пытаться восстановиться.
SK>чтобы не быть голословным, вот например, код операции, которая возвращает размер массива(из openjdk):
SK>
То, что вы привели — это код интерпретатора. Интерпретатор работает в самом начале. Как только обнаружен метод, выполняемый много раз, он компилируется в машинные коды. Вот найдите соответствующий кусок компилятора (кодогенератора) и посмотрим, генерится ли там проверка на null, или полагаются на аппаратную проверку.
SK>Видите CHECK_NULL после того как ссылку забрали со стека? SK>Еще стоит посмотреть, на месте в коде jdk где используется, виндовый SEH. Он как раз и отлавливает те самые исключения о которых вы говорите — EXCEPTION_ACCESS_VIOLATION, EXCEPTION_INT_DIVIDE_BY_ZERO и т.д. В этом коде и следа нет прокидывания этих исключений дальше.
Спасибо, ровно так, как я предполагал.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, StanislavK, Вы писали:
SK>>>Я вот вас опять не понимаю. Вроде серьезный мужчина, а троллите. PD>>Я Вас тоже. Вроде серьезная дискуссия, а Вы прибегаете к таким аргументам... SK>это и не аргумет вовсе.
Равно как и Ваш. Мне кажется, лучше вообще было не начинать эти инвективы в мой адрес.
SK>Откуда вы все это взяли? Точнее откуда взяли понятно, но кто вам сказал, что ява так работает? Если в яве машине возникнет обращение по несуществующему адресу или деления на ноль, то процесс упадет, в лучшем случае, скинув дамп и немного диагностики. После такого никто в своем уме не будет пытаться восстановиться. А выглядеть это будет вот так (или так):
SK>Видите CHECK_NULL после того как ссылку забрали со стека?
Да, по-видимому Вы правы.
В сущности есть 4 вида исключений процессора, которые портируются в прикладную программу
(1) не с нулевым указателем в яве невозможно
(2) и (4) вполне контролируемы обычным if
(3) неконтролируемо (поди пойми, будет в умножении overflow или нет — не логарифмы же вычислять!), но в яве с этим обошлись установкой режима FPU, когда вместо overflow возвращают NAN.
Вот с null — другое дело. Контролировать, конечно, несложно, но контролировать на каждой операции довольно-таки накладно. Допускаю, что ява-машина контролирует не на каждой, хотя и не очень легко привести случай, когда можно не контролировать. Решение, конечно, эффективное, но уж очень дорогое. В нативном коде так не делают : там либо обращаются напрямую по адресу в твердой уверенности, что адрес корректен, либо пытаются обратиться по адресу, который может быть и NULL, тогда ловят исключение и исправляют в обработчике исключения. Ява так не делает. Ясно.
PD>Вот с null — другое дело. Контролировать, конечно, несложно, но контролировать на каждой операции довольно-таки накладно. Допускаю, что ява-машина контролирует не на каждой, хотя и не очень легко привести случай, когда можно не контролировать. Решение, конечно, эффективное, но уж очень дорогое. В нативном коде так не делают : там либо обращаются напрямую по адресу в твердой уверенности, что адрес корректен, либо пытаются обратиться по адресу, который может быть и NULL, тогда ловят исключение и исправляют в обработчике исключения. Ява так не делает. Ясно.
Ну, как уже говорили, джит для конкретной системы и конкретной аппаратной платформы может и соптимизировать, но в общем случае мы имеем лекгопортируемое безопасное решение(if — он совсем мультиплатформенный, т.е. скомпиляется где угодно), а это основа джавы.
Хотя мне кажется, что в джит не станет заморачиваться с нативными исключениями(оно же еще и для разных архитектур и систем отличаться будет), а просто, зная достоверно дерево исполнения в текущем запущенном приложении, просто уберет к чертям ненужные проверки. Причем операция в рантайме минимкм на порядок более простая, чем для статического компилятора(например, все ссылки, которые уже инициализированы, и нигде не переопределяются, гарантированно уже валидные до конца работы, хотя при другом запуске может быть иначе — а джит обычно пробегает по уже давно инициализированному приложению, т.е. это не проблема). В Скале вообще с этим проще — там форсируется использование val(это аналог final в джаве) вместо var(переменная, т.е. может быть переопределена). И когда в коде 99% неизменяемых значений, задача еще более упрощается(заодно с многопоточностью несколько спокойнее, но это другой разговор).
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Eugeny__, Вы писали:
E__>Ну, как уже говорили, джит для конкретной системы и конкретной аппаратной платформы может и соптимизировать, но в общем случае мы имеем лекгопортируемое безопасное решение(if — он совсем мультиплатформенный, т.е. скомпиляется где угодно), а это основа джавы.
Да, только это значит, что проверки на кажлм обращении.
E__>Хотя мне кажется, что в джит не станет заморачиваться с нативными исключениями(оно же еще и для разных архитектур и систем отличаться будет), а просто, зная достоверно дерево исполнения в текущем запущенном приложении, просто уберет к чертям ненужные проверки. Причем операция в рантайме минимкм на порядок более простая, чем для статического компилятора(например, все ссылки, которые уже инициализированы, и нигде не переопределяются, гарантированно уже валидные до конца работы,
Слишком жесткое условие. Конечно, если они не переопределяются, это верно. Только вот определить, переопределяются они или нет, далеко не всегда так уж просто
>хотя при другом запуске может быть иначе — а джит обычно пробегает по уже давно инициализированному приложению, т.е. это не проблема).
Эту фразу я не понял. Если при другом запуске может быть иначе, то когда он пробегает ? Если при запуске(после инициализации), то еще ничего не известно ("может быть иначе"). Если же он во время работы то и дело пробегает по инициализированному приложению — когда именно ?
E__>>Ну, как уже говорили, джит для конкретной системы и конкретной аппаратной платформы может и соптимизировать, но в общем случае мы имеем лекгопортируемое безопасное решение(if — он совсем мультиплатформенный, т.е. скомпиляется где угодно), а это основа джавы.
PD>Да, только это значит, что проверки на кажлм обращении.
В режиме интерпритатора. На самом деле, не так уж все тяжко, проверка на ноль — легкая операция. Учитывая нишу джавы(сервера и обработка тонн текста), это ни о чем даже в интерпритации.
E__>>Хотя мне кажется, что в джит не станет заморачиваться с нативными исключениями(оно же еще и для разных архитектур и систем отличаться будет), а просто, зная достоверно дерево исполнения в текущем запущенном приложении, просто уберет к чертям ненужные проверки. Причем операция в рантайме минимкм на порядок более простая, чем для статического компилятора(например, все ссылки, которые уже инициализированы, и нигде не переопределяются, гарантированно уже валидные до конца работы,
PD>Слишком жесткое условие. Конечно, если они не переопределяются, это верно. Только вот определить, переопределяются они или нет, далеко не всегда так уж просто
Зная все дерево исполнения? Легче легкого. Это же байткод, а не асм(или тем более С++ код), там вручную человеку можно это установить за небольшое время, машине на это нужны наносекунды.
>>хотя при другом запуске может быть иначе — а джит обычно пробегает по уже давно инициализированному приложению, т.е. это не проблема).
PD>Эту фразу я не понял. Если при другом запуске может быть иначе, то когда он пробегает ? Если при запуске(после инициализации), то еще ничего не известно ("может быть иначе"). Если же он во время работы то и дело пробегает по инициализированному приложению — когда именно ?
Джит пробегает по часто выполняемому коду, т.е. по "узким горлышкам"(остальное выполняет интерпритер, бо нет смысла компилить в рантайме код, занимающий по процовому времени тысячные проценты от общего времени). Приложение к этому времени обычно уже подняло и инициализировало все свои компоненты(из конфигов, из сети, и с чертовых куличек), и значения многих переменных известны. Если нигде в загруженном коде нет установки значения переменной, то все проверки на ноль можно убрать, выполняя рантайм-компиляцию. Если код перезагружен(например, веб-серверу переложили файл с приложением), то, полагаю, все скомпиленное отменяется.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, StanislavK, Вы писали:
PD>1) access violation PD>(1) не с нулевым указателем в яве невозможно
Теоретически возможно. Это будет означать проблему в JVM.
PD>Вот с null — другое дело. Контролировать, конечно, несложно, но контролировать на каждой операции довольно-таки накладно. Допускаю, что ява-машина контролирует не на каждой, хотя и не очень легко привести случай, когда можно не контролировать. Решение, конечно, эффективное, но уж очень дорогое. В нативном коде так не делают : там либо обращаются напрямую по адресу в твердой уверенности, что адрес корректен, либо пытаются обратиться по адресу, который может быть и NULL, тогда ловят исключение и исправляют в обработчике исключения. Ява так не делает. Ясно.
JVM так не делает еще потому, что Access Violation совсем не значит, что обратились по нулевому указателю.
PD>Вопрос же вот какой. Почему-то абсолютно отсутствует какая бы то ни было выдача по случаю самого NPE.
Потому что:
1. Разработчики Concurrency API — не Ванга и не знают, какой вам нужен способ обработки исключений и чем он лучше других способов.
2. Если вас волнует результат выполнения задачи (исключение тоже является результатом), вы по определению должны использовать FutureTask.
3. Если вас интересует появление исключений непосредственно в нити выполнения задачи, вы пишете свой try-catch в её реализации.
4. Пп. 2-3 полностью закрывают все потребности разработчиков, поэтому в добавлении в API каких-то дополнительных обработчиков нет смысла.
Здравствуйте, Eugeny__, Вы писали:
E__>Джит пробегает по часто выполняемому коду, т.е. по "узким горлышкам"(остальное выполняет интерпритер, бо нет смысла компилить в рантайме код, занимающий по процовому времени тысячные проценты от общего времени). Приложение к этому времени обычно уже подняло и инициализировало все свои компоненты(из конфигов, из сети, и с чертовых куличек), и значения многих переменных известны. Если нигде в загруженном коде нет установки значения переменной, то все проверки на ноль можно убрать, выполняя рантайм-компиляцию. Если код перезагружен(например, веб-серверу переложили файл с приложением), то, полагаю, все скомпиленное отменяется.
Если речь идёт о локальных переменных, проблем нет. Если речь идёт о полях, их может поменять код, например, через рефлексию, а это уже невозможно отследить предварительным анализом. Никаких предположений о том, что полям не присваивается NULL, VM делать не может. Поэтому либо будут проверки, либо будет ловиться аппаратное исключение и преобразовываться в JVM исключение (я не гуру машинного кода, но вроде бы тут никаких особенных проблем не должно возникнуть, ситуация для процессора вполне обычная).
Здравствуйте, vsb, Вы писали:
vsb>Если речь идёт о локальных переменных, проблем нет. Если речь идёт о полях, их может поменять код, например, через рефлексию, а это уже невозможно отследить предварительным анализом.
Теоретически, JVM вполне может при попытке доступа к полю через рефлексию отменять такие спекулятивные оптимизации.
Практически же я вообще сильно сомневаюсь что у JITа есть время анализировать все загруженные классы на предмет наличия присваиваний.
Здравствуйте, StanislavK, Вы писали:
PD>>1) access violation PD>>(1) не с нулевым указателем в яве невозможно SK>Теоретически возможно. Это будет означать проблему в JVM.
Да. Манипулируя в свое время с unsafe (не помню имя класса, что-то из sun.misc кажется) я его получил. Но это уж мои проблемы.
PD>>Вот с null — другое дело. Контролировать, конечно, несложно, но контролировать на каждой операции довольно-таки накладно. Допускаю, что ява-машина контролирует не на каждой, хотя и не очень легко привести случай, когда можно не контролировать. Решение, конечно, эффективное, но уж очень дорогое. В нативном коде так не делают : там либо обращаются напрямую по адресу в твердой уверенности, что адрес корректен, либо пытаются обратиться по адресу, который может быть и NULL, тогда ловят исключение и исправляют в обработчике исключения. Ява так не делает. Ясно. SK>JVM так не делает еще потому, что Access Violation совсем не значит, что обратились по нулевому указателю.
Вот это как раз выяснить в обработчике нативного исключения можно. По крайней мере для Windows.
Здравствуйте, RomikT, Вы писали:
RT>Здравствуйте, vsb, Вы писали:
vsb>>Если речь идёт о локальных переменных, проблем нет. Если речь идёт о полях, их может поменять код, например, через рефлексию, а это уже невозможно отследить предварительным анализом. RT>Теоретически, JVM вполне может при попытке доступа к полю через рефлексию отменять такие спекулятивные оптимизации. RT>Практически же я вообще сильно сомневаюсь что у JITа есть время анализировать все загруженные классы на предмет наличия присваиваний.
Нафига все-то? Просто хук на рефлексию поставить для этого поля. Рефлексия и так не самая скоростная штука, еще одна проверка ей сильно не помешает, зато поможет в оптимизации в рантайме.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Eugeny__, Вы писали:
E__>Здравствуйте, RomikT, Вы писали:
RT>>Здравствуйте, vsb, Вы писали:
vsb>>>Если речь идёт о локальных переменных, проблем нет. Если речь идёт о полях, их может поменять код, например, через рефлексию, а это уже невозможно отследить предварительным анализом. RT>>Теоретически, JVM вполне может при попытке доступа к полю через рефлексию отменять такие спекулятивные оптимизации. RT>>Практически же я вообще сильно сомневаюсь что у JITа есть время анализировать все загруженные классы на предмет наличия присваиваний.
E__>Нафига все-то? Просто хук на рефлексию поставить для этого поля.
Что все? Оптимизации? Потому что речь шла об оптимизациях, основанных на предположении о неизменности поля, поэтому его запись естетсвенно должна отменять все такие оптимизации. Именно в виде хука на рефлексию.