Java işlemi zarif bir şekilde nasıl durdurulur?


88

Linux ve Windows'ta bir Java sürecini nasıl düzgün bir şekilde durdurabilirim?

Ne zaman aranıyor Runtime.getRuntime().addShutdownHookve ne zaman aranmıyor?

Sonlandırıcılar ne olacak, burada yardımcı oluyorlar mı?

Java sürecine kabuktan bir çeşit sinyal gönderebilir miyim?

Tercihen taşınabilir çözümler arıyorum.


Ne demek istediğinizi gerçekten zarif bir şekilde tanımlamalısınız. (lütfen)
Henry B

7
Program sonlandırılmadan önce bir kaynağı temizleme, serbest bırakma, kilitleme ve kalıcı verileri diske temizleme şansı verilmesini istediklerini varsayıyorum.
Steve g

Yanıtlar:


82

Kapatma kancaları, VM'nin zorla öldürülmediği tüm durumlarda yürütülür. Yani, eğer "standart" bir öldürme ( SIGTERMbir öldürme komutundan) verecekseniz, o zaman çalıştırılacaktır. Benzer şekilde, arandıktan sonra çalıştırılırlar System.exit(int).

Ancak zor bir öldürme ( kill -9veya kill -SIGKILL) o zaman idam edilmezler. Benzer şekilde (ve tabii ki) gücü bilgisayardan çekerseniz, kaynayan lav dolu bir fıçıya atarsanız veya CPU'yu bir balyozla parçalara ayırırsanız çalışmazlar. Muhtemelen bunu zaten biliyordunuz.

Sonlandırıcılar gerçekten de çalışmalıdır, ancak kapatma temizliği için buna güvenmemek en iyisidir, bunun yerine işleri temiz bir şekilde durdurmak için kapatma kancalarınıza güvenmek en iyisidir. Ve her zaman olduğu gibi, kilitlenmelere karşı dikkatli olun (çok fazla kapatma kancasının tüm süreci askıya aldığını gördüm)!


1
Ne yazık ki, bu Windows 7'de (64bit) çalışmıyor gibi görünüyor. Görev listesini kuvvet bayrağı olmadan kullanmayı denedim ve şu hatayla karşılaştım: "HATA: PID 14324 ile işlem sonlandırılamadı. Neden: Bu işlem yalnızca zorla sonlandırılabilir (/ F seçeneğiyle)." "/ F" kuvvet seçeneğini sağlamak, süreci anında kapatacaktır.
Jason Huntley

Sonlandırıcıların çalıştırılmasına güvenemezsiniz.
Thorbjørn Ravn Andersen

47

Tamam, "Java İzleme ve Yönetimi" ile çalışmayı seçtiğim tüm olasılıklardan sonra
Genel Bakış burada
Bu, bir uygulamayı diğerinden nispeten kolay bir şekilde kontrol etmenizi sağlar. Kontrollü uygulamayı sonlandırmadan önce incelikli bir şekilde durdurmak için bir komut dosyasından kontrol uygulamasını çağırabilirsiniz.

İşte basitleştirilmiş kod:

Kontrollü uygulama:
Aşağıdaki VM parametreleriyle çalıştırın:
-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");
    }
}
}

Uygulamayı Kontrol:
ile çalıştırmak durdurmak veya başlatmak komut satırı argümanı olarak

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();
    }
}
}


Bu kadar. :-)


7

Başka bir yol: uygulamanız bir sunucu grubu açabilir ve ona bir bilginin gelmesini bekleyebilir. Örneğin "sihirli" kelimeye sahip bir dize :) ve ardından kapatma yapmak için tepki verin: System.exit (). Bu tür bilgileri, telnet gibi harici bir uygulama kullanarak çorba gönderebilirsiniz.


3

İşte biraz zor ama taşınabilir bir çözüm:

  • Uygulamanızda bir kapatma kancası uygulayın
  • JVM'nizi düzgün bir şekilde kapatmak istediğinizde , Attach API'yi kullanarak System.exit () öğesini çağıran bir Java Aracısı yükleyin .

Java Aracısını uyguladım. Github'da mevcuttur: https://github.com/everit-org/javaagent-shutdown

Çözümle ilgili ayrıntılı açıklamayı burada bulabilirsiniz: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/


2

Benzer Soru Burada

Java'daki sonlandırıcılar kötüdür. Çöp toplamaya çok fazla ek yük eklerler. Mümkün olduğunca onlardan kaçının.

ShutdownHook yalnızca VM kapatılırken çağrılır. Bence istediğini yapabileceğini düşünüyorum.


1
Yani shutdownHook TÜM durumlarda çağrılıyor? Ya işlemi kabuktan 'öldürürse'?
Ma99uS

Pekala, eğer onu öldürürsen değil -9 :)
Steve g

0

Linux'ta sinyalizasyon "kill" (mevcut sinyaller için adam öldürme) ile yapılabilir, bunu yapmak için işlem kimliğine ihtiyacınız olacaktır. (ps ax | grep java) veya bunun gibi bir şey veya işlem oluşturulduğunda işlem kimliğini saklayın (bu, çoğu linux başlangıç ​​dosyasında kullanılır, bkz. /etc/init.d)

Taşınabilir sinyalizasyon, Java uygulamanıza bir SocketServer entegre edilerek yapılabilir. O kadar da zor değil ve size istediğiniz herhangi bir komutu gönderme özgürlüğü veriyor.

Sonuçlandırıcılar yerine nihayet hükümleri kastetmişseniz; System.exit () çağrıldığında çalıştırılmazlar. Sonlandırıcılar çalışmalı, ancak gerçekten daha önemli bir şey yapmamalı, ancak bir hata ayıklama ifadesi yazdırmalıdır. Tehlikelidirler.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.