Java에서 종료 후크의 유용한 예?


126

내 Java 응용 프로그램이 견고 해지기 위해 합리적인 단계를 수행하도록 노력하고 있으며 그 중 일부는 정상적으로 종료되는 것과 관련이 있습니다. 셧다운 훅 에 대해 읽고 있는데 실제로 사용하는 방법을 알지 못합니다.

거기에 실용적인 예가 있습니까?

아래와 같은 정말 간단한 응용 프로그램이 있다고 가정 해 보겠습니다.이 응용 프로그램은 파일에 10, 한 줄에 100 개의 일괄 처리로 숫자를 기록하고 프로그램이 중단되면 지정된 일괄 처리가 완료되는지 확인하고 싶습니다. 종료 후크를 등록하는 방법을 얻었지만이를 내 응용 프로그램에 통합하는 방법을 모릅니다. 어떤 제안?

package com.example.test.concurrency;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

public class GracefulShutdownTest1 {
    final private int N;
    final private File f;
    public GracefulShutdownTest1(File f, int N) { this.f=f; this.N = N; }

    public void run()
    {
        PrintWriter pw = null;
        try {
            FileOutputStream fos = new FileOutputStream(this.f);
            pw = new PrintWriter(fos);
            for (int i = 0; i < N; ++i)
                writeBatch(pw, i);
        }
        catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        finally
        {
            pw.close();
        }       
    }

    private void writeBatch(PrintWriter pw, int i) {
        for (int j = 0; j < 100; ++j)
        {
            int k = i*100+j;
            pw.write(Integer.toString(k));
            if ((j+1)%10 == 0)
                pw.write('\n');
            else
                pw.write(' ');
        }
    }

    static public void main(String[] args)
    {
        if (args.length < 2)
        {
            System.out.println("args = [file] [N] "
                    +"where file = output filename, N=batch count");
        }
        else
        {
            new GracefulShutdownTest1(
                    new File(args[0]), 
                    Integer.parseInt(args[1])
            ).run();
        }
    }
}

답변:


160

다음을 수행 할 수 있습니다.

  • 종료 후크가 일부 AtomicBoolean (또는 휘발성 부울) "keepRunning"을 false로 설정하도록합니다.
  • (선택적 .interrupt으로 일부 차단 호출에서 데이터를 기다리는 경우 작업 스레드)
  • 작업 스레드 writeBatch에서 Thread.join()메서드를 호출 하여 작업 스레드 ( 귀하의 경우 실행 )가 완료 될 때까지 기다 립니다.
  • 프로그램 종료

몇 가지 간단한 코드 :

  • 을 추가하다 static volatile boolean keepRunning = true;
  • 에서 실행 () 당신은 변경

    for (int i = 0; i < N && keepRunning; ++i)
        writeBatch(pw, i);
  • 에서 ) (주 당신은 추가 :

    final Thread mainThread = Thread.currentThread();
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            keepRunning = false;
            mainThread.join();
        }
    });

이것이 내가 터미널에서 "Control-C를 눌렀을 때 모든 클라이언트를 거부"하는 방법입니다.


에서 워드 프로세서 :

가상 머신이 종료 시퀀스를 시작하면 등록 된 모든 종료 후크가 지정되지 않은 순서로 시작되고 동시에 실행됩니다. 모든 후크가 완료되면 종료시 종료가 활성화 된 경우 호출되지 않은 모든 종료자를 실행합니다. 마지막으로 가상 머신이 중지됩니다.

즉, 종료 후크는 후크가 종료 될 때까지 ( run () 메서드 에서 반환 될 때까지) JVM을 계속 실행합니다 .


14
아-내가 옳게 이해한다면, 당신이 말하는 것의 요지는 종료 후크가 현재 실행중인 다른 스레드와 통신하고 VM 종료를 보류 할 수있는 기회가 있다는 것입니다 (예 : Thread.join () 사용). ) 빠른 정리가 완료되었다고 만족할 때까지. 그게 제가 놓친 포인트입니다. 감사!
— 제이슨 S

2
예. 맞아요. 문서의 몇 문장으로 답변을 업데이트했습니다.
— aioobe

1
미리 죄송하지만 GracefulShutdownTest1이 Runnable을 구현해서는 안 되나요?
— Victor '

메인 스레드에서 GUI가 시작된 경우에도 작동합니까? 나는 그것이 최선의 방법이 아니라는 것을 알고 있지만 (대신 EDT 사용), 나는 오래된 코드를 작업하고 있습니다.
— Agostino 2014 년

1
@ MartynasJusevičius, 모든 비 데몬 스레드가 종료되면 JVM이 종료됩니다. (가) 경우 mainThread데몬 스레드는 다음 join을 보장 우리는 JVM이 종료시키기 전에 마무리로 나올 때까지 기다리는 것이.
— aioobe 19

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.