Как прекратить Java-процесс изящно?

Как прекратить процесс Java изящно в Linux и Windows?

Когда вызывается Runtime.getRuntime().addShutdownHook, а когда нет?

Как насчет финализаторов, они здесь помогают?

Можно ли отправить какой-то сигнал в процесс Java из оболочки?

Я ищу предпочтительные портативные решения.

Ответ 1

Ключи выключения выполняются во всех случаях, когда виртуальная машина не принудительно убита. Итак, если вы должны были выдать "стандартное" kill (SIGTERM из команды kill), то они будут выполняться. Точно так же они будут выполняться после вызова System.exit(int).

Однако жесткое убийство (kill -9 или kill -SIGKILL), то они не будут выполняться. Точно так же (и, очевидно) они не будут выполняться, если вы вытащите власть из компьютера, выбросите ее в чану кипящей лавы или побейте CPU на куски кувалдой. Вы, наверное, уже это знали.

Финализаторы действительно должны работать так же хорошо, но лучше не полагаться на это для очистки выключения, а скорее полагаться на свои крючки остановки, чтобы прекратить все чисто. И, как всегда, будьте осторожны с тупиками (я видел, что слишком много остановок перехватывают весь процесс)!

Ответ 2

Хорошо, после всех возможностей, которые я выбрал для работы с "Мониторинг и управление Java"
Обзор здесь
Это позволяет вам управлять одним приложением из другого путем относительно простым способом. Вы можете вызвать управляющее приложение из script, чтобы прекратить контролируемое приложение изящно, прежде чем убить его.

Вот упрощенный код:

Управляемое приложение:
запустите его с помощью следующих параметров VM:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port = 9999
-Dcom.sun.management.jmxremote.authenticate = ложь
-Dcom.sun.management.jmxremote.ssl = ложь

//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");
    }
}
}

Управление приложением:
запустите его с помощью остановки или запуска в качестве аргумента командной строки

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


Это.:-)

Ответ 3

Другой способ: ваше приложение может открыть серверный сервер и дождаться получения информации. Например, строка с "магическим" словом:) и затем реагируют на завершение работы: System.exit(). Вы можете отправить такую ​​информацию в socke с помощью внешнего приложения, такого как telnet.

Ответ 4

Подобный вопрос Здесь

Финализаторы в Java плохо. Они добавляют много накладных расходов на сбор мусора. Избегайте их, когда это возможно.

ShutdownHook будет вызван только при отключении виртуальной машины. Я думаю, что он очень хорошо может делать то, что вы хотите.

Ответ 6

Вот немного сложное, но портативное решение:

  • В вашем приложении реализуется хук остановки
  • Если вы хотите изящно отключить JVM, установите Java Agent, который вызывает System.exit(), используя Прикрепить API.

Я реализовал Java-агент. Он доступен в Github: https://github.com/everit-org/javaagent-shutdown

Подробное описание решения можно найти здесь: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/

Ответ 7

Сигнализация в Linux может быть выполнена с помощью "kill" (man kill для доступных сигналов), для этого вам потребуется идентификатор процесса. (ps ax | grep java) или что-то в этом роде или сохранить идентификатор процесса при создании процесса (это используется в большинстве файлов запуска Linux, см. /etc/init.d)

Портативная сигнализация может быть выполнена путем интеграции SocketServer в ваше Java-приложение. Это не так сложно и дает вам свободу отправлять любую команду, которую вы хотите.

Если вы имели в виду окончательные предложения вместо финализаторов; они не выдаются при вызове System.exit(). Финализаторы должны работать, но не должны делать ничего более значительного, но печатать отладку. Они опасны.

Ответ 8

Спасибо за ответы. Отключить крючки швов, как что-то, что будет работать в моем случае. Но я также столкнулся с тем, что называется "Мониторинг и управление" beans:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Это дает хорошие возможности для удаленного мониторинга и манипулирования процессом Java. (Был представлен на Java 5)