Bagaimana cara menghentikan proses java dengan anggun?


88

Bagaimana cara menghentikan proses Java dengan baik di Linux dan Windows?

Kapan Runtime.getRuntime().addShutdownHook dipanggil, dan kapan tidak?

Bagaimana dengan finalisator, apakah mereka membantu di sini?

Dapatkah saya mengirim semacam sinyal ke proses Java dari shell?

Saya mencari solusi yang lebih disukai portabel.


Anda harus benar-benar mendefinisikan apa yang Anda maksud dengan anggun. (tolong)
Henry B

7
Saya berasumsi maksudnya mereka ingin diberi kesempatan untuk membersihkan sumber daya, melepaskan, mengunci, dan membuang data yang ada ke disk sebelum program dimatikan.
Steve g

Jawaban:


82

Hook shutdown dijalankan di semua kasus di mana VM tidak dibunuh secara paksa. Jadi, jika Anda mengeluarkan kill "standar" ( SIGTERMdari perintah kill) maka mereka akan mengeksekusi. Demikian pula, mereka akan mengeksekusi setelah memanggil System.exit(int).

Bagaimanapun hard kill ( kill -9atau kill -SIGKILL) maka mereka tidak akan mengeksekusi. Demikian pula (dan jelas) mereka tidak akan dijalankan jika Anda menarik daya dari komputer, menjatuhkannya ke dalam tong lava mendidih, atau memukul CPU menjadi beberapa bagian dengan palu godam. Anda mungkin sudah tahu itu.

Finalizer benar-benar harus berjalan juga, tetapi yang terbaik adalah tidak bergantung pada itu untuk pembersihan shutdown, melainkan mengandalkan hook shutdown Anda untuk menghentikan semuanya dengan bersih. Dan, seperti biasa, berhati-hatilah dengan kebuntuan (saya telah melihat terlalu banyak kait penghentian yang menggantung seluruh proses)!


1
Sayangnya, ini sepertinya tidak berfungsi pada Windows 7 (64bit). Saya telah mencoba menggunakan taskill, tanpa flag force, dan menemukan error berikut: "ERROR: Proses dengan PID 14324 tidak dapat dihentikan. Alasan: Proses ini hanya dapat dihentikan secara paksa (dengan opsi / F)." Memberikan opsi gaya, "/ f", jelas akan menutup proses secara instan.
Jason Huntley

Anda tidak dapat mengandalkan finalisator yang dijalankan.
Thorbjørn Ravn Andersen

47

Ok, setelah semua kemungkinan yang saya pilih untuk bekerja dengan "Pemantauan dan Manajemen Java"
Ikhtisar ada di sini
Yang memungkinkan Anda untuk mengontrol satu aplikasi dari yang lain dengan cara yang relatif mudah. Anda dapat memanggil aplikasi pengontrol dari skrip untuk menghentikan aplikasi yang dikontrol dengan baik sebelum mematikannya.

Berikut kode yang disederhanakan:

Aplikasi yang dikontrol:
jalankan dengan parameter VM berikut:
-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");
    }
}
}

Mengontrol aplikasi:
jalankan dengan berhenti atau mulai sebagai argumen baris perintah

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


Itu dia. :-)


7

Cara lain: aplikasi Anda dapat membuka server socet dan menunggu informasi sampai padanya. Misal string dengan kata "ajaib" :) kemudian bereaksi membuat shutdown: System.exit (). Anda dapat mengirimkan informasi tersebut ke kaus kaki menggunakan aplikasi eksternal seperti telnet.



2

Pertanyaan Serupa Disini

Finalisator di Java buruk. Mereka menambahkan banyak biaya tambahan untuk pengumpulan sampah. Hindari mereka jika memungkinkan.

ShutdownHook hanya akan dipanggil saat VM dimatikan. Saya pikir itu sangat baik mungkin melakukan apa yang Anda inginkan.


1
Jadi shutdownHook dipanggil dalam SEMUA kasus? Bagaimana jika 'membunuh' proses dari shell?
Ma99uS

Yah, tidak jika Anda mencobanya -9 :)
Steve g

0

Pensinyalan di Linux dapat dilakukan dengan "kill" (man kill untuk sinyal yang tersedia), Anda memerlukan ID proses untuk melakukannya. (ps ax | grep java) atau semacamnya, atau simpan id proses saat proses dibuat (ini digunakan di sebagian besar file startup linux, lihat /etc/init.d)

Pensinyalan portabel dapat dilakukan dengan mengintegrasikan SocketServer dalam aplikasi java Anda. Tidak sesulit itu dan memberi Anda kebebasan untuk mengirim perintah apa pun yang Anda inginkan.

Jika yang Anda maksud akhirnya adalah klausul sebagai ganti finalizer; mereka tidak dieksekusi ketika System.exit () dipanggil. Finalizer seharusnya berfungsi, tetapi seharusnya tidak melakukan sesuatu yang lebih signifikan selain mencetak pernyataan debug. Mereka berbahaya.


0

Terima kasih atas jawaban Anda. Penutup kait penutup seperti sesuatu yang akan bekerja dalam kasus saya. Tetapi saya juga menemukan sesuatu yang disebut kacang Pemantauan dan Manajemen:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Itu memberikan beberapa kemungkinan bagus, untuk pemantauan jarak jauh, dan manipulasi dari proses java. (Diperkenalkan di Java 5)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.