Làm thế nào để dừng quá trình java một cách duyên dáng?


88

Làm cách nào để dừng quá trình Java một cách dễ dàng trong Linux và Windows?

Khi nào thì Runtime.getRuntime().addShutdownHookđược gọi, và khi nào thì không?

Còn những người hoàn thiện, họ có giúp gì ở đây không?

Tôi có thể gửi một số loại tín hiệu đến một quy trình Java từ một trình bao không?

Tôi đang tìm kiếm các giải pháp di động tốt hơn.


bạn thực sự nên xác định ý mình một cách duyên dáng. (làm ơn)
Henry B

7
Tôi cho rằng họ muốn có cơ hội dọn dẹp tài nguyên, giải phóng, khóa và xóa bất kỳ dữ liệu liên tục nào vào đĩa trước khi chương trình bị giết.
Steve g

Câu trả lời:


82

Các móc tắt thực thi trong mọi trường hợp mà máy ảo không bị giết một cách cưỡng bức. Vì vậy, nếu bạn đưa ra một lệnh kill "tiêu chuẩn" ( SIGTERMtừ lệnh kill) thì chúng sẽ thực thi. Tương tự, chúng sẽ thực thi sau khi gọi System.exit(int).

Tuy nhiên, một hard kill ( kill -9hoặc kill -SIGKILL) thì chúng sẽ không thực hiện. Tương tự (và rõ ràng là) chúng sẽ không thực thi nếu bạn rút nguồn điện từ máy tính, thả nó vào một thùng dung nham đang sôi hoặc đập CPU thành nhiều mảnh bằng búa tạ. Bạn có thể đã biết điều đó, mặc dù.

Các trình hoàn thiện thực sự cũng nên chạy, nhưng tốt nhất không nên dựa vào đó để dọn dẹp tắt máy, mà hãy dựa vào các móc tắt máy của bạn để dừng mọi thứ một cách sạch sẽ. Và, như mọi khi, hãy cẩn thận với các deadlock (tôi đã thấy có quá nhiều shutdown hook làm treo toàn bộ quá trình)!


1
Thật không may, điều này dường như không hoạt động trên Windows 7 (64bit). Tôi đã thử sử dụng taskill mà không có cờ force và gặp lỗi sau: "LỖI: Không thể kết thúc quá trình với PID 14324. Lý do: Chỉ có thể kết thúc quá trình này một cách cưỡng bức (với tùy chọn / F)." Việc cung cấp tùy chọn lực lượng, "/ f", rõ ràng sẽ đóng quá trình ngay lập tức.
Jason Huntley,

Bạn không thể dựa vào các trình hoàn thiện đang được chạy.
Thorbjørn Ravn Andersen

47

Ok, sau tất cả các khả năng tôi đã chọn để làm việc với "Giám sát và quản lý Java"
Tổng quan ở đây
Điều đó cho phép bạn kiểm soát một ứng dụng từ một ứng dụng khác một cách tương đối dễ dàng. Bạn có thể gọi ứng dụng điều khiển từ một tập lệnh để dừng ứng dụng được điều khiển một cách duyên dáng trước khi giết nó.

Đây là mã đơn giản:

Ứng dụng được kiểm soát:
chạy nó với các tham số VM sau:
-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");
    }
}
}

Kiểm soát ứng dụng:
chạy nó với dừng hoặc bắt đầu làm đối số dòng lệnh

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


Đó là nó. :-)


7

Một cách khác: ứng dụng của bạn có thể mở một máy chủ và đợi thông tin đến với nó. Ví dụ một chuỗi có từ "ma thuật" :) và sau đó phản ứng để thực hiện tắt máy: System.exit (). Bạn có thể gửi thông tin như vậy đến socke bằng một ứng dụng bên ngoài như telnet.


3

Đây là một giải pháp hơi phức tạp, nhưng linh hoạt:

  • Trong ứng dụng của bạn, hãy triển khai một hook tắt máy
  • Khi bạn muốn tắt JVM của mình một cách dễ dàng, hãy cài đặt Java Agent gọi System.exit () bằng cách sử dụng API Đính kèm .

Tôi đã triển khai Java Agent. Nó có sẵn trên Github: https://github.com/everit-org/javaagent-shutdown

Mô tả chi tiết về giải pháp có tại đây: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/


2

Câu hỏi tương tự tại đây

Trình hoàn thiện trong Java không tốt. Họ thêm rất nhiều chi phí vào việc thu gom rác. Tránh chúng bất cứ khi nào có thể.

ShutdownHook sẽ chỉ được gọi khi VM đang tắt. Tôi nghĩ rằng nó rất tốt có thể làm những gì bạn muốn.


1
Vậy shutdownHook được gọi trong TẤT CẢ các trường hợp? Điều gì sẽ xảy ra nếu 'giết' quá trình từ trình bao?
Ma99uS

Chà, không phải nếu bạn đang cho nó giết -9 :)
Steve g

0

Báo hiệu trong Linux có thể được thực hiện bằng "kill" (giết người cho các tín hiệu có sẵn), bạn cần có ID quy trình để thực hiện điều đó. (ps ax | grep java) hoặc thứ gì đó tương tự, hoặc lưu trữ id quy trình khi quy trình được tạo (điều này được sử dụng trong hầu hết các tệp khởi động linux, xem /etc/init.d)

Báo hiệu di động có thể được thực hiện bằng cách tích hợp SocketServer trong ứng dụng java của bạn. Nó không quá khó và cho phép bạn tự do gửi bất kỳ lệnh nào bạn muốn.

Nếu bạn muốn nói mệnh đề cuối cùng thay vì kết thúc; chúng không được thực thi khi System.exit () được gọi. Trình hoàn thiện sẽ hoạt động, nhưng không thực sự nên làm bất cứ điều gì quan trọng hơn ngoài việc in một câu lệnh gỡ lỗi. Chúng nguy hiểm.


0

Cảm ơn câu trả lời của bạn. Tắt móc nối các đường nối giống như một cái gì đó sẽ hoạt động trong trường hợp của tôi. Nhưng tôi cũng gặp phải một thứ gọi là đậu Giám sát và Quản lý:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Điều đó mang lại một số khả năng tốt đẹp, để giám sát và thao tác từ xa của quy trình java. (Đã được giới thiệu trong Java 5)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.