Java'da bir kapatma kancasına faydalı bir örnek?


126

Java uygulamamın sağlam olmak için makul adımlar attığından emin olmaya çalışıyorum ve bunun bir parçası da nazikçe kapatmayı içeriyor. Hakkında okuyorumKapatma kancaları ve pratikte bunları nasıl kullanacağımı bilmiyorum.

Orada pratik bir örnek var mı?

Diyelim ki, aşağıdaki gibi gerçekten basit bir uygulamam vardı, sayıları bir dosyaya, 10'u bir satıra, 100'lük gruplar halinde yazıyor ve program kesintiye uğrarsa, belirli bir partinin bitmesini sağlamak istiyorum. Bir kapatma kancasını nasıl kaydedeceğimi anlıyorum, ancak bunu uygulamama nasıl entegre edeceğime dair hiçbir fikrim yok. Baska öneri?

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

Yanıtlar:


160

Şunları yapabilirsiniz:

  • Kapatma kancasının bazı AtomicBoolean (veya geçici boolean) "keepRunning" değerini false olarak ayarlamasına izin verin
  • (İsteğe bağlı olarak, .interruptçalışan iş parçacıkları bir engelleme çağrısında veri beklerlerse)
  • Çalışma iş parçacıkları üzerindeki yöntemi writeBatchçağırarak , çalışan iş parçacıklarının ( sizin durumunuzda çalıştırılan ) bitmesini bekleyin Thread.join().
  • Programı sonlandırın

Bazı kabataslak kod:

  • Ekle static volatile boolean keepRunning = true;
  • In vadede () Eğer değiştirmek

    for (int i = 0; i < N && keepRunning; ++i)
        writeBatch(pw, i);
  • In ) (ana Eklemek:

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

Kabaca bu şekilde, terminalde "Control-C'ye basıldığında tüm istemcileri reddet" şeklinde zarif bir şekilde yaparım.


Gönderen docs :

Sanal makine kapatma sırasına başladığında, tüm kayıtlı kapatma kancalarını belirtilmemiş bir sırada başlatacak ve eşzamanlı olarak çalışmasına izin verecektir. Tüm kancalar bittiğinde, çıkışta sonlandırma etkinleştirilmişse tüm çağrılmamış sonlandırıcıları çalıştıracaktır. Son olarak, sanal makine duracaktır.

Diğer bir deyişle, bir kapatma kancası, kanca sona erene kadar ( run () yönteminden dönene kadar JVM'yi çalışır durumda tutar.


14
Ah - eğer doğru anladıysam, söylediklerinizin özü, kapatma kancasının şu anda çalışan diğer iş parçacıklarıyla iletişim kurma ve VM kapanmasını durdurma (örneğin Thread.join () kullanarak) fırsatı olduğudur. ) hızlı bir temizliğin tamamlandığı tatmin edilene kadar. İşte kaçırdığım nokta buydu. Teşekkürler!
Jason S

2
Evet. Anladın. Yanıtı dokümanlardan birkaç cümleyle güncelledi.
aioobe

1
Şimdiden özür dilerim, ancak GracefulShutdownTest1 Runnable'ı uygulamamalı mı?
Victor

Bu aynı zamanda ana iş parçacığında başlatılan bir GUI çalışacak mı? Bunu yapmanın en iyi yolu olmadığını biliyorum (bunun yerine EDT kullanın), ancak eski kod üzerinde çalışıyorum.
Agostino

1
@ MartynasJusevičius, JVM, arka plan programı olmayan tüm iş parçacıkları sona erdiğinde sona erer. Eğer mainThreadbir cin iplik, sonra joingaranti biz JVM kapatmaya izin vermeden önce bitirmek için bunun için beklemeniz.
aioobe

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.