2012-01-17 5 views
1

У меня есть следующий код:Настройка ShutdownHook и выхода из приложения

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, это должно быть очень простое приложение, потому что оно будет использоваться для сеансов удаленных подключенных окон.

Есть ли у вас какие-либо предположения для фона, ожидающего завершения регистрации?

ответ

2

ShutdownHook является поток, который выполняется, когда JVM покидает и программа ничего после того, как вы выполняете «SendMessage» не делает:

sendMessage(event, getCurrentLogin()); 

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

0

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

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

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

0

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

while (true) { 
    //Your logic here 
} 

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

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

-1

Вот один подход с использованием 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(); 
} 
+1

Вы избили меня к нему :-) – Scorpion

+0

Я не вижу обработку для InterruptedException? – Scorpion

1

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

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

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

это не скомпилируется, потому что защелка не является окончательной. См. Мой ответ для правильного пути;) – dogbane

+0

Исправил его, и я не дал отговорки, что это просто дать идею, а не рабочее решение. – Scorpion

0

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

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

Если вы не хотите, чтобы ваша программа немедленно выходила, то main придется зацикливаться и ждать какого-то сигнала.Из контекста вашего вопроса, я думаю, он должен слушать какой-то ответ от звонка sendMessage? Если вы хотите ждать, нажмите Ctrl + 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(); 
     } 
    } 
} 

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