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.