Настройка ShutdownHook и выход из приложения - PullRequest
1 голос
/ 17 января 2012

У меня есть следующий код:

public static void main(String[] args) {

    // login event
    String event = "login";
    System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
    sendMessage(event, getCurrentLogin());

    // logout or shutdown event
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
                String event = "logout";
                System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
        }
    }));
 }

Это очень простая программа для регистрации входа и выхода пользователя из системы.Проблема в том, что программа завершается, когда достигает конца функции main ().

Правильно ли я использую для подключения события завершения работы?Я не хочу создавать сложную службу Windows, это должно быть очень простое приложение, потому что оно будет использоваться для удаленных подключенных сеансов Windows.

Есть ли у вас какие-либо предположения о фоновом ожидании завершения входа в систему?

Ответы [ 6 ]

2 голосов
/ 17 января 2012

ShutdownHook - это поток, который выполняется, когда JVM завершает работу, и программа ничего не делает после выполнения команды «sendMessage»:

sendMessage(event, getCurrentLogin());

Вам следует дождаться выхода сигнала, например, Ctrl + C на консоли. Просто дождитесь блокировки или семафора, чтобы избежать завершения программы, и эта блокировка должна быть снята, когда вам нужно ее завершить.

1 голос
/ 17 января 2012

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

РЕДАКТИРОВАТЬ: Пример ниже будет печатать как логин и выход из системы.

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

    public class Test {
        public static void main(String[] args) throws Exception {

            // login event
            String event = "login";
            System.out.printf("Handling event: %s %s\n", event, getCurrentLogin());
            sendMessage(event, getCurrentLogin());
            final CountDownLatch latch = new CountDownLatch(1);

            // logout or shutdown event
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    String event = "logout";
                    System.out.printf("Handling event: %s %s\n", event, getCurrentLogin());
                    sendMessage(event, getCurrentLogin());
                    latch.countDown();
                }
            }));
            latch.await(2, TimeUnit.SECONDS);
        }

        private static void sendMessage(String event, Object currentLogin) {
        }

        private static Object getCurrentLogin() {
            return "X";
        }
    }
0 голосов
/ 18 января 2012

Здесь есть несколько хороших ответов, но я все еще вижу недостающую информацию.

Ваш код регистрирует отключение в main, после чего main достигает конца и возвращается. Хуки завершения вызываются, когда выходит последний поток, не являющийся демоном. Я подозреваю, что main является единственным потоком, не являющимся демоном, поэтому при выходе из main ловушка вызывается немедленно.

Если вы не хотите, чтобы ваша программа выходила немедленно, тогда main придется зацикливаться и ждать какого-то сигнала. Из контекста вашего вопроса, я полагаю, он должен прислушиваться к какому-то ответу на звонок sendMessage? Если вы хотите дождаться control-c, тогда мне нравится ответ @JB Nizet:

public static void main(String[] args) throws InterruptedException {
    ...
    Runtime.getRuntime().addShutdownHook(...);
    // wait until control-c is called
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}

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

0 голосов
/ 17 января 2012

Вот один из подходов, использующий CountDownLatch для ожидания основного потока:

public static void main(String[] args) {

    // login event
    String event = "login";
    System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
    sendMessage(event, getCurrentLogin());

    final CountDownLatch latch = new CountDownLatch(1);

    // logout or shutdown event
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
                String event = "logout";
                System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
                latch.countDown();
        }
    }));

    latch.await();
 }
0 голосов
/ 17 января 2012

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

while (true) {
    //Your logic here
}

Если вы хотите написать демон или планировщик, возможно, вам нужно использовать какой-то фреймворк как Quartz http://quartz-scheduler.org

Если вы хотите реализовать демон, вы можете использовать Service Wrapper, например, http://yajsw.sourceforge.net или http://wrapper.tanukisoftware.com/

0 голосов
/ 17 января 2012

Если я правильно понимаю, вы хотите бесконечно ждать, пока ОС остановит вашу программу, верно? Если это так, вам нужно запустить хотя бы один поток демонов:

public static void main(String[] args) throws InterruptedException {
    //...
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}

Я не уверен, что операционная система достаточно аккуратно убьет JVM, и, тем не менее, хук отключения будет выполнен. Проверьте это.

...