Soru JVM daemon iplerini nasıl sona erdiriyor? veya incelikle sonlanan daemon iş parçacığı nasıl yazılır


Varsayımsal senaryo:
Bazı I / O'lardan sorumlu bir iş parçacığım var, ana iş parçacığı sona eriyor ve geri dönüyor ve JVM daemon dizimi sonlandırmaya karar veriyor.

Bunu nasıl yapıyor? Kesmek? Sonuçlandırmak? Daemon iş parçamı, sonlandırıldığında incelikle yanıt verecek şekilde nasıl kodlayabilirim?


28
2017-12-29 01:27


Menşei


Kaynak koduna baktın mı? - Stephen C
@StephenC Bana gelmemişti ve kesinlikle kesin bir cevap verecekti. zorunlu olarak kullanışlı bir tane). Ancak ben şahsen, bunu yapmaya yetecek kadar cesur değilim ve başka kimsenin beklemesini istemiyorum. - Aaron J Lang
Tamam, daha açık bir şekilde olalım. Böyle bir soruyu cevaplamanın en iyi yolu, kaynak koduna veya en azından Java koduna bakmaktır. Genel olarak, okunması ve yorumlanması kolaydır. (Ve bir soruya kesin bir cevabın kesin olmayan birinden nasıl daha az yararlı olduğunu anlamıyorum. sen kodu okuyan kişi vardı!) - Stephen C
OP'ye kaynak koduna bakmanın cevabı yok. Bu, API gerekliliklerini değil, belirli bir uygulamayı gösterir. Belgelerin yeri var. - Raedwald


Cevaplar:


Aşağıdaki kodu bir test olarak yazdım:

public class DaemonThreadPlay {
    public static void main(String [] args) {
        Thread daemonThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        System.out.println("Try block executed");
                        Thread.sleep(1000l);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            }

            @Override
            public void finalize() {
                System.out.println("Finalize method called");
            }
        };
        daemonThread.setDaemon(true);
        daemonThread.start();

        try {
            Thread.sleep(2500l);
        } catch (Throwable t) {
            //NO-OP
        }
    }
}    

Daemon iş parçacığının yakalama bloğuna ve sonlandırma yöntemine kesme noktaları koyuyorum. Deneme bloğu yürütüldüğünde, her iki noktaya da ulaşılmadı. Açıkçası bu kodun senkronizasyon / zamanlama sorunları var, ama bence daemon iş parçacığının kapanmada kesintiye uğramadıklarını ya da kesin olarak sonuçlandırılan finalize () yöntemlerinin olduğu sonucuna varabiliriz.

JVM Çalışma Zamanı'na her zaman bir kapatma kancası ekleyebilirsiniz:

Thread shutdownHook = ... // construct thread that somehow
                          // knows about all the daemon threads
Runtime.getRuntime().addShutdownHook(shutdownHook);

Kapatma kancınız, açıkça "zarif" bir kapatma için gerekli olan görevleri yapabilir.


11
2017-12-29 01:51



Kapatma çengelini beğeniyorum. - Bob Kuhar
Bulunan bu aktif konuları almanın yollarını ararken. En az bir kullanıcı iş parçacığı kontrol etmek için dizi üzerinde yineleme gerekir. <br/> Kapatma çengelinin en iyi çözüm olduğunu düşünüyorum, daha önce bu işlevselliği hiç bilmiyordum. Ana sınıfımdaki kapatma kancama bir referans göstereceğim ve daemon ipliklerimin bir koleksiyonunu kapatma kancasında saklayacağım. Sonra hepsini kesebilirim. Bunu uyguladıktan sonra kodumu göndermeyi deneyeceğim. - Aaron J Lang
Ararsan System.gc() açıkça ve JVM seçeneği -XX:+DisableExplicitGC ayarlanmadı, sonra daemon ipliği çıkacak. Bu, Çöp Toplayıcı tüm kullanıcı konuları bitirdikten sonra daemon ipliklerini kapatmaktan sorumludur. - George
Yapabileceğiniz başka bir şey, sonunda bir blok oluşturmak, bu try-catch bloğu içinde ne olur ne olursa olsun çağrılması garantilidir! Bu şekilde Daemon iş parçacığının açtığı tüm kaynakları kapatabilir ve orada herhangi bir zarif sonlandırma uygulayabilirsiniz! - Hass Joseph K.


Bir daemon parçasının ne olduğunu yanlış anladın.

Görmek java daemon ipliği nedir

Özet olarak, temel olarak bir daemon iş parçacığının hiçbir G / Ç yapmaması veya kaynak tutmaması gerektiği anlamına gelir. Bu temel kurala aykırı davranıyorsanız, iş parçanız bir daemon iş parçacığı olmayı hak etmiyor.

Bir kapatma kancası eklemek, kodunuzun JVM sonlandırmasından önce çağrılmasını sağlamanın standart yoludur, ancak bu bile% 100 garantili değildir - JVM'niz örneğin OS'yi işletim sistemini koruyacak şekilde toparlamak için çökebilir. Ancak, büyük olasılıkla uygulamanızı tutarsız / hatalı durumda bırakır.

Sistem denetim ve kurtarma mekanizmaları, yazılımın ilk günlerine (örneğin işletim sistemleri ve parti işlemleri) geri döner ve maalesef bu tekerlek, bu sorunu ele alan "gümüş mermi" yaklaşımı (API) olmadığı için yeniden icat edilir. genel yol.


5
2017-08-28 21:18



Daemon iş parçacığının IO yapmaması ya da kaynakları tutmaması gerektiği iddiasının temeli nedir? - ykaganovich
Sağlanan bağlantıyı takip edin ve bazı bilgiler elde edersiniz. - user924272
üzgünüm, katılmıyorum. Bir Daemon ipliğinin orta süreçte öldürülebileceği anlaşıldığı sürece, java kaynağı sızıntısı hakkında bir şey bilmediğiniz sürece tehlike yoktur. - ykaganovich
Daemon ipliği yüzlerce kaynağı tutuyorsa, daha da kötüsü, kritik yazma işlemlerinin bir dizisinin ortasında gerçekleştiğinde, kapatma işlemi JVM'yi sonlandırmak için deliliktir. Uygulamanızdaki bir tutarlılık noktasını etkili bir şekilde riske atıyorsunuz. “Java Concurrency in Practice” yazısını yazan Brian Goetz ile de aynı fikirde değilsiniz ... buna katılmamak çok güzel, ancak haklı olabileceğiniz çok az sayıda vaka olduğunu düşünüyorum. - user924272


AFAIK, Daemon konuları ana akım I / O çalışması için değil. Tüm dişler tamamlandığında, JVM tüm daemon ipliklerini aniden kapatabilir. İhtiyaçlarınız için olası çalışma aşağıdaki gibi bir ExecutorService oluşturacaktır:

ExecutorService execPool = Executors.newSingleThreadExecutor(new ThreadFactory() {

    @Override    
    public Thread newThread(Runnable runnable) {       
         Thread thread = Executors.defaultThreadFactory().newThread(runnable);
         thread.setDaemon(true);
         return thread;    
    } 
}); 

Kapatma çengelinden executorservice kapatma yöntemini çağırır.

Runtime.getRuntime().addShutdownHook(....)

4
2017-12-29 02:08



newThread yönteminiz gerçekten her zaman yeni bir iplik fabrikası oluşturur. bir çağrı Executors.defaultThreadFactory() sadece bir döner new DefaultThreadFactory() - benez


interrupt kullanın ve katılın:

class Daemon extends Thread {
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println(e);
                break;
            }
        }
        System.out.println("exit run()");
    }
}   
public class So8663107 {
    public static void main(String[] arguments) throws InterruptedException {
        System.out.println(Thread.activeCount());
        Daemon daemon = new Daemon();
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(2500);
        System.out.println(Thread.activeCount());
        daemon.interrupt();
        daemon.join();
        System.out.println(Thread.activeCount());
    }
}

1
2017-12-29 02:10



Soruyu anladın sanırım. Daemon thread'larımı kesmek istemiyorum. JVM'nin onları nasıl sonlandıracağını ve bunun nasıl ele alınacağını bilmek istiyorum. - Aaron J Lang
üzgünüm, cevap vermeye çalışıyordum: "Daemon iş parçamı nasıl inceler, böylece incelikle sona erer mi?" - Ray Tayek
Tamam, soruyu düzenledim - Aaron J Lang