2008-10-10 12 views
82

Jak zatrzymać proces Java z łatwością w systemach Linux i Windows?Jak z wdziękiem zatrzymać proces java?

Kiedy zostaje wywołana Runtime.getRuntime().addShutdownHook, a kiedy nie?

A co z finalizatorami, czy oni tu pomagają?

Czy mogę wysłać jakiś sygnał do procesu Java z powłoki?

Poszukuję przenośnych rozwiązań.

+0

naprawdę należy określić, co masz na myśli przez wdziękiem. (proszę) –

+6

Zakładam, że mają na myśli, że chcą mieć możliwość oczyszczenia zasobów, zwolnienia, zablokowania i wypłukania wszystkich trwałych danych na dysk, zanim program zostanie zabity. –

Odpowiedz

72

Haki zamykające są wykonywane we wszystkich przypadkach, w których maszyna wirtualna nie została zabita siłą. Tak więc, jeśli miałbyś wydać "standardowe" zabójstwo (SIGTERM z komendy kill), to one zostaną wykonane. Podobnie będą one wykonywane po wywołaniu System.exit(int).

Jednak trudne zabójstwo (kill -9 lub kill -SIGKILL) nie spowoduje ich wykonania. Podobnie (i oczywiście) nie zostaną wykonane, jeśli wyciągniesz zasilanie z komputera, wrzucisz je do garnka wrzącej lawy lub pokonasz procesor na kawałki za pomocą młota. Prawdopodobnie już to wiedziałeś.

Finalizery również powinny działać, ale najlepiej nie polegać na tym przy czyszczeniu po zamknięciu, ale raczej polegać na hakach wyłączania, aby zatrzymać wszystko w sposób czysty. I, jak zawsze, uważaj na zakleszczenia (widziałem zbyt wiele haczyków wyłączających cały proces)!

+0

Niestety, to nie działa na Windows 7 (64-bitowy). Próbowałem używać taskill, bez flagi siły, i napotkałem następujący błąd: "BŁĄD: Proces z PID 14324 nie mógł zostać zakończony Powód: Ten proces może zostać zakończony tylko z użyciem opcji/F)." Dostarczenie opcji siły, "/ f", oczywiście natychmiast zamknie proces. –

+0

Nie można polegać na uruchamianych finalizatorach. –

2

Podobne pytanie Here

finalizatory w Javie są złe. Dodają wiele kosztów do zbierania śmieci. Unikaj ich, gdy tylko jest to możliwe.

Klawisz shutdownHook zostanie wywołany tylko po wyłączeniu VM. Myślę, że bardzo dobrze może robić to, co chcesz.

+1

Więc shutdownHook zostaje wywołany w WSZYSTKICH przypadkach? Co jeśli "zabić" proces z powłoki? – Ma99uS

+0

Cóż, nie, jeśli dajesz mu zabójstwo -9 :) –

0

Sygnalizacja w Linuksie można zrobić z „kill” (człowiek zabić dostępnych sygnałów), to trzeba identyfikator procesu, aby to zrobić. (ps ax | grep java) lub coś w tym stylu, lub przechowaj identyfikator procesu po utworzeniu procesu (jest on używany w większości plików startowych Linux-a, patrz /etc/init.d)

Przenośna sygnalizacja może być wykonana przez integrację serwera SocketServer w aplikacji java. To nie jest takie trudne i daje swobodę wysyłania dowolnych poleceń.

Jeśli miałeś na myśli ostatecznie klauzule zamiast finalizatorów; nie są wykonywane, gdy wywoływana jest funkcja System.exit(). Finalizery powinny działać, ale nie powinny robić nic bardziej znaczącego, ale powinny wydrukować instrukcję debugowania. Są niebezpieczne.

46

Ok, po wszystkich możliwości, zdecydowałem się pracować z „Monitoring Java i Zarządzania”
Overview is here
który pozwala kontrolować jeden wniosek z innym w stosunkowo prosty sposób. Możesz zadzwonić do aplikacji kontrolującej ze skryptu, aby z wdziękiem zatrzymać kontrolowaną aplikację, zanim ją zabijesz.

Oto uproszczony kod:

Kontrolowane zastosowanie:
uruchomić go z folowing parametrów VM:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote .port = 9999
-Dcom.sun.management.jmxremote.authenticate = false
-Dcom.sun.management.jmxremote.ssl = false

//ThreadMonitorMBean.java 
public interface ThreadMonitorMBean 
{ 
String getName(); 
void start(); 
void stop(); 
boolean isRunning(); 
} 

// ThreadMonitor.java 
public class ThreadMonitor implements ThreadMonitorMBean 
{ 
private Thread m_thrd = null; 

public ThreadMonitor(Thread thrd) 
{ 
    m_thrd = thrd; 
} 

@Override 
public String getName() 
{ 
    return "JMX Controlled App"; 
} 

@Override 
public void start() 
{ 
    // TODO: start application here 
    System.out.println("remote start called"); 
} 

@Override 
public void stop() 
{ 
    // TODO: stop application here 
    System.out.println("remote stop called"); 

    m_thrd.interrupt(); 
} 

public boolean isRunning() 
{ 
    return Thread.currentThread().isAlive(); 
} 

public static void main(String[] args) 
{ 
    try 
    { 
     System.out.println("JMX started"); 

     ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread()); 

     MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 

     ObjectName name = new ObjectName("com.example:type=ThreadMonitor"); 

     server.registerMBean(monitor, name); 

     while(!Thread.interrupted()) 
     { 
      // loop until interrupted 
      System.out.println("."); 
      try 
      { 
       Thread.sleep(1000); 
      } 
      catch(InterruptedException ex) 
      { 
       Thread.currentThread().interrupt(); 
      } 
     } 
    } 
    catch(Exception e) 
    { 
     e.printStackTrace(); 
    } 
    finally 
    { 
     // TODO: some final clean up could be here also 
     System.out.println("JMX stopped"); 
    } 
} 
} 

Kontrolowanie aplikacji:
uruchomić go z przystanku lub startowym jako argument wiersza poleceń

public class ThreadMonitorConsole 
{ 

public static void main(String[] args) 
{ 
    try 
    { 
     // connecting to JMX 
     System.out.println("Connect to JMX service."); 
     JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi"); 
     JMXConnector jmxc = JMXConnectorFactory.connect(url, null); 
     MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); 

     // Construct proxy for the the MBean object 
     ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor"); 
     ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true); 

     System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running"); 

     // parse command line arguments 
     if(args[0].equalsIgnoreCase("start")) 
     { 
      System.out.println("Invoke \"start\" method"); 
      mbeanProxy.start(); 
     } 
     else if(args[0].equalsIgnoreCase("stop")) 
     { 
      System.out.println("Invoke \"stop\" method"); 
      mbeanProxy.stop(); 
     } 

     // clean up and exit 
     jmxc.close(); 
     System.out.println("Done.");  
    } 
    catch(Exception e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 
} 


to wszystko. :-)

7

Innym sposobem: twoja aplikacja może otworzyć serwer i czekać na informacje dotarły do ​​niego. Na przykład ciąg znaków z "magicznym" słowem :), a następnie reaguj, aby zamknąć: System.exit(). Możesz wysłać takie informacje do skarpety za pomocą zewnętrznej aplikacji, takiej jak telnet.

Powiązane problemy