Коллекция не повторяется в хуке завершения работы Java

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

1 вкладыш: мой крючок отключения, по-видимому, отключен до того, как завершит свою работу.

Код, который я запускаю, выглядит так:

class Test {

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(Test::shutdown));
    }

    // more methods
    private static void shutdown() {
        Collection<Foo> coll = some.instance.ofHashMap.values();
        System.out.println("collSize=" + coll.size());
        for (Foo o : coll) {
            System.out.println("Calling bar on foo");
            o.bar();
        }
        System.out.println("End of hook");
    }
}

Но на выходе получается:

collSize=1

Если я запустил jvm с опцией -server, мне может повезти, и напечатает «Панель вызовов на foo», но она все равно не напечатает «Конец перехвата».

К сожалению, мне не удалось создать короткий исполняемый пример, показывающий проблему. У меня есть один, но он показывает, что все работает нормально, и коллекция повторяется, как и ожидалось. Приведенный выше код представляет собой отрывок из гораздо более крупной программы, над которой я работаю, но мое отключение - это крючок, который не делает ничего, кроме приведенного выше (получить непустую коллекцию и повторить).

Есть идеи о том, что может происходить? Я совершенно потерялся здесь ...

Примечания: - Код написан, скомпилирован и запущен для / с Java 8u45 - Я убиваю программу с помощью Ctrl + C, в результате JVM существует с кодом 130


person fabien    schedule 02.10.2015    source источник
comment
Коллекция модифицируется несколькими потоками?   -  person Dici    schedule 02.10.2015
comment
Между вызовом coll.size () и итерацией есть интервал. Нет никакой гарантии, что коллекция не будет изменена между ними. (Это, по крайней мере, теоретическая возможность, и, поскольку вы не можете привести краткий пример, можно сомневаться.)   -  person laune    schedule 02.10.2015
comment
На данный момент коллекция ничем не модифицируется, если только волшебный поток (который я не кодировал) не удаляет из нее элементы. На самом деле нет кода, который удаляет элементы из этой коллекции.   -  person fabien    schedule 02.10.2015
comment
Вы контролируете код, который заполняет / возвращает эту коллекцию?   -  person Dici    schedule 02.10.2015
comment
Можете ли вы добавить еще один объект Foo к объекту коллекции, а затем перебрать его, чтобы проверить, что именно он печатает, 1 объект или 2? Вы добавляете его после System.out.println (collSize = + coll.size ()); Линия...   -  person developer    schedule 02.10.2015
comment
Вы должны просто отладить это ...   -  person wero    schedule 02.10.2015
comment
Извините, ребята, мой пример был плохим и не описывал, что на самом деле происходит. Я обновил сообщение новой информацией.   -  person fabien    schedule 02.10.2015
comment
Действительно ли виртуальная машина выходит чисто? Отображаются ли другие сообщения? Какое событие вызывает завершение работы виртуальной машины (нормальный выход или завершение работы системой)? Наблюдаете ли вы такое же поведение, если опустите вызов o.bar() в своем цикле?   -  person John Bollinger    schedule 02.10.2015
comment
Может быть, это просто проблема ввода-вывода? Может быть, ловушка выполняет всю свою работу, но сообщения о ходе выполнения не доходят до консоли.   -  person John Bollinger    schedule 02.10.2015
comment
Виртуальная машина существует чисто с кодом 130 (я нажимаю Ctrl + C, чтобы убить ее, и хочу освободить некоторые ресурсы, когда это произойдет). Никаких аварийных журналов, никаких исключений.   -  person fabien    schedule 02.10.2015
comment
Похоже, o.bar() заблокирован и не вернулся. Любые (локальные) ресурсы будут очищены ОС при завершении процесса, поэтому не беспокойтесь о них (дескрипторы открытых файлов, сокеты и т. Д.)   -  person dsh    schedule 02.10.2015


Ответы (2)


Из документы (выделено мной) вам обещают только лучшие усилия для хуков выключения:

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

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

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

person Gus    schedule 02.10.2015
comment
Я пытаюсь освободить кучу ресурсов, когда пользователь убивает виртуальную машину с помощью Ctrl + C. Время не проблема. Я могу заставить крючок ждать 5 секунд, но он все еще полностью выполнен. То, что я пытаюсь запустить, в любом случае очень быстрое ... - person fabien; 02.10.2015

Оказывается:

  • в основном это была проблема ввода-вывода: в отличие от примера выше, я использую регистратор из log4j2 для печати информации. log4j2 имеет свой собственный shutdownHook, который убивает все регистраторы быстрее, чем мой обработчик выключения, поскольку хуки выключения выполняются параллельно в JVM. После отключения log4j2 shutdownHook все заработало, как ожидалось.
  • ловушка всегда выполнялась полностью (легко проверяется подключением отладчика к jvm)
  • в моем конкретном случае я забыл завершить работу + ожидание в моих пулах потоков, чтобы выполнить всю очистку, которую я хотел
  • я должен был выспаться на нем, прежде чем размещать здесь: /

Спасибо всем за быстрые ответы и помощь.

person fabien    schedule 04.10.2015