Değilse, Java Thread interrupt () yöntemini kim çağırıyor?


87

Pratikte Java Eşzamanlılığını okudum ve yeniden okudum, burada konuyla ilgili birkaç iş parçacığı okudum, InterruptedException ile uğraşmak için IBM makalesini okudum ve yine de anlamadığım ve kırılabileceğini düşündüğüm bir şey var iki soruya bölünür:

  1. Diğer iş parçacıklarını asla kendim kesmiyorsam, InterruptedException'ı ne tetikleyebilir ?

  2. Interrupt () kullanarak diğer iş parçacıklarını asla kesintiye uğratmazsam ( örneğin, zehirli haplar ve while (! İptal edildi) tarzı döngü [ikisi de JCIP'de açıklandığı gibi] gibi çalışan iş parçacıklarımı iptal etmek için başka yöntemler kullandığım için ), ne bir gelmez InterruptedException sonra demek? Birini yakaladığımda ne yapmalıyım? Uygulamamı kapat?

Yanıtlar:


51

İplik kesme mekanizması, yaptığı şeyi durdurma isteğine yanıt vermek için (işbirliği yapan) bir iş parçacığı elde etmenin tercih edilen yoludur. Herhangi bir iş parçacığı (sanırım iş parçacığı dahil) interrupt()bir İş Parçacığını arayabilir .

Pratikte, normal kullanım durumları interrupt(), bir tür çerçeve veya yöneticinin, bazı çalışan iş parçacığına yaptıklarını durdurmasını söyler. Çalışan iş parçacığı "kesinti farkındaysa", bir istisna yoluyla veya kesintiye uğrayan bayrağını periyodik olarak kontrol ederek kesintiye uğradığını fark edecektir. Kesildiğini fark eden iyi huylu bir ileti dizisi yaptığı şeyi bırakıp kendi kendini bitirir.

Yukarıdaki kullanım durumunu varsayarsak, kodunuz bir Java çerçevesinde veya bazı çalışan iş parçacığından çalıştırılırsa büyük olasılıkla kesintiye uğrayacaktır. Ve kesintiye uğradığında, kodunuz yapmakta olduğu şeyi bırakmalı ve en uygun yollarla kendisinin bitmesine neden olmalıdır. Kodunuzun nasıl çağrıldığına bağlı olarak, bu, geri dönülerek veya bazı uygun istisnalar atılarak yapılabilir. Ama muhtemelen aramamalı System.exit(). (Uygulamanız neden kesintiye uğradığını bilmeyebilir ve çerçeve tarafından kesintiye uğratılması gereken başka iş parçacığı olup olmadığını kesinlikle bilmez.)

Öte yandan, kodunuz bazı çerçevelerin kontrolü altında çalışacak şekilde tasarlanmamışsa InterruptedException, bunun beklenmedik bir istisna olduğunu iddia edebilirsiniz ; yani bir hata. Bu durumda, istisnayı diğer hatalar gibi ele almalısınız; örneğin, onu kontrol edilmemiş bir istisnaya sarın ve diğer beklenmedik kontrol edilmemiş istisnalarla uğraştığınız noktada yakalayın ve günlüğe kaydedin. (Alternatif olarak, uygulamanız kesmeyi yok sayabilir ve yaptığı şeyi yapmaya devam edebilir.)


1) Diğer iş parçacıklarını asla kendim kesmiyorsam, InterruptedException'ı ne tetikleyebilir?

Senin eğer bir örneği olduğunu Runnablenesneler bir kullanılarak yürütülür ExecutorServiceve shutdownNow()hizmet denir. Ve teoride, herhangi bir 3. taraf iş parçacığı havuzu veya iş parçacığı yönetimi çerçevesi yasal olarak böyle bir şey yapabilir.

2) Interrupt () kullanarak diğer iş parçacıklarını asla kesmiyorsam ... InterruptedExceptiono zaman ne anlama geliyor? Birini yakaladığımda ne yapmalıyım? Uygulamamı kapat?

interrupt()Aramaları neyin neden yaptığını anlamak için kod tabanını analiz etmeniz gerekir . Bunu anladıktan sonra, uygulamanızın << bölümünün ne yapması gerektiğini >> hesaplayabilirsiniz.

Neden InterruptedExceptionatıldığını anlayana kadar, bunu zor bir hata olarak ele almanızı tavsiye ederim; örneğin, günlük dosyasına bir yığın izi yazdırın ve uygulamayı kapatın. (Açıkçası, bu her zaman doğru cevap değildir ... ama asıl mesele şu ki, bu "bir hata" ve geliştiricinin / bakımcının dikkatine sunulması gerekiyor.)

3) Kimin / neyin aradığını nasıl öğrenebilirim interrupt()?

Buna iyi bir cevap yok. Önerebileceğim en iyi şey Thread.interrupt(), çağrı yığınına bir kesme noktası ayarlamak ve buna bakmaktır.


12

Kodunuzu diğer kitaplıklarla entegre etmeye karar verirseniz, kodunuzu çağırabilirler interrupt(). Örneğin, ileride kodunuzu bir ExecutorService içinde çalıştırmaya karar verirseniz, bu , üzerinden bir kapanmaya zorlayabilir interrupt().

Kısaca söylemek gerekirse, sadece kodunuzun şu anda nerede çalıştığını değil, gelecekte hangi bağlamda çalışabileceğini düşüneceğim . örneğin onu bir kütüphaneye mi koyacaksınız? Konteyner mi? Başkaları onu nasıl kullanacak? Yeniden kullanacak mısın?


Yalnızca shutdownNow'un interrupt () yöntemini çağırdığını düşündüm. Kapatma için de doğru mu?
Harinder

9

Başkalarının da belirttiği gibi, bir iş parçacığını kesmek (aslında, bloke eden bir çağrıyı kesmek) genellikle temiz bir şekilde çıkmak veya devam eden bir etkinliği iptal etmek için kullanılır.

Ancak, InterruptedExceptiontek başına bir "çıkma komutu" olarak davranmamalısınız . Bunun yerine, kesmeleri iş parçacıklarının çalışma durumunu kontrol etmenin bir yolu olarak düşünmelisiniz, aynı şekilde Object.notify(). Bir çağrıdan uyandıktan sonra mevcut durumu kontrol ettiğiniz gibi (uyanmanın Object.wait()bekleme koşulunuzun yerine getirildiği anlamına geldiğini varsaymazsınız), bir kesinti ile dürtüklendikten sonra neden kesintiye uğradığınızı kontrol etmelisiniz. . Bunu yapmanın genellikle bir yolu vardır. Örneğin java.util.concurrent.FutureTaskbir isCancelled()metodu var.

Kod örneği:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}

3

Soruyla ilgili sorun "ben" dir. "I" genellikle bir sınıfın tek bir örneğini ifade eder. Bununla demek istediğim, herhangi bir düşük seviyeli kod (sınıf) parçası, tüm sistemin uygulanmasına dayanmamalıdır. Bazı "mimari" kararlar vermiş olduğunuzu söyledikten sonra (hangi platformda çalışacağınız gibi).

JRE'den gelen olası beklenmedik kesintiler, uygulamalarda iptal edilen java.util.concurrentve kapatılan görevlerdir .

İş parçacığı kesintilerinin işlenmesi genellikle yanlış yazılır. Bu nedenle, mümkün olduğunca kesintilere neden olmamak için mimari kararı öneriyorum. Bununla birlikte, kod işleme kesintileri her zaman doğru yazılmalıdır. Kesintileri artık platformdan çıkaramıyorum.


Ben atmak zorunda asla: doğrusu,) Well; Selam Tom, cljp adınızı hatırlar ) (kesme Ben bir InterruptedException ve gereğini biniyorum sürece yeniden assert kesintiye durumu ... kendimi ama bu hala% 100'dür bana açık. Burada yeniyim ve olumlu oyların ve cevapların / yorumların (hem doğru hem de yanlış olanlar) sayısı beni şaşırttı: açıkçası önemsiz olmayan veya en azından genellikle iyi açıklanmayan bir konu. Bu, tüm gönderiler sayesinde neler olup bittiğine dair daha net bir resim elde etmeye başladığımı söyledi :)
SözdizimiT3rr0r

3

Bunu, kendi iş parçacığı sınıfınızı (genişletme java.lang.Thread) oluşturarak ve interrupt()yığın izini örneğin bir String alanına kaydettiğiniz ve ardından super.interrupt () 'a transfer ettiğiniz geçersiz kılma yöntemini oluşturarak öğrenebilirsiniz .

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}

1

Daha önce de belirtildiği gibi, başka bir kitaplık iş parçacıklarınızı kesebilir. Kitaplığın kodunuzdan iş parçacıklarına açık erişimi olmasa bile, çalışan iş parçacıklarının listesini yine de aşağıdaki yöntemle bu şekilde kesebilir .


1

Sanırım kesinti konusunda kafanızın neden biraz karışık olduğunu anlıyorum. Lütfen cevaplarımı şu satırda değerlendirin:

Diğer iş parçacıklarını asla kendim kesmiyorsam, InterruptedException'ı ne tetikleyebilir ?

Öncelikle diğer konuları kesebilirsiniz; JCiP'de sahip olmadığınız konuları asla kesmemeniz gerektiğinden bahsedildiğini biliyorum; ancak bu ifade tam olarak anlaşılmalıdır. Bunun anlamı, herhangi bir gelişigüzel iş parçacığında çalışan kodunuzun kesintiyi ele almaması gerektiğidir, çünkü iş parçacığının sahibi olmadığı için kesinti politikasına dair hiçbir ipucu yoktur. Bu nedenle, diğer iş parçacıklarında kesinti talep edebilirsiniz, ancak kesinti eylemini sahibinin yapmasına izin verin; sizin görev kodunuz değil, kesinti politikasına sahiptir; en azından kesinti bayrağını koymak için nazik olun!

Hala kesintilerin olmasının birçok yolu vardır, zaman aşımları, JVM kesintileri vb. Olabilir.

Interrupt () kullanarak diğer iş parçacıklarını asla kesintiye uğratmazsam (örneğin, zehirli haplar ve while (! İptal edildi) tarzı döngü [ikisi de JCIP'de açıklandığı gibi] gibi çalışan iş parçacıklarımı iptal etmek için başka yöntemler kullandığım için), ne InterruptedException demek? Birini yakaladığımda ne yapmalıyım? Uygulamamı kapat?

Burada çok dikkatli olmalısın; InterruptedException (IE) atan iş parçacığına sahipseniz, yakalandıktan sonra ne yapacağınızı biliyorsunuz, örneğin uygulamanızı / hizmetinizi kapatabileceğinizi veya bu kesilen iş parçacığını yenisiyle değiştirebileceğinizi söyleyin! Bununla birlikte, iş parçacığına sahip değilseniz, IE'yi yakaladıktan sonra ya çağrı yığınını yeniden fırlatın ya da bir şey yaptıktan sonra (günlük kaydı olabilir), kesintiye uğramış durumu sıfırlayın, böylece kontrol ona ulaştığında bu iş parçacığına sahip olan kod olabilir, iş parçacığının kesintiye uğradığını öğrenin ve kesinti politikasını yalnızca o bildiği için gerektiği gibi harekete geçin.

Umarım bu yardımcı olmuştur.


0

InterruptedExceptionRutin söylüyor olabilir kesintiye ama mutlaka olacaktır.

Kesmeyi beklemiyorsanız, başka herhangi bir beklenmedik istisna gibi davranmalısınız. Beklenmeyen bir istisnanın kötü sonuçlara yol açabileceği kritik bir bölümdeyse, kaynakları denemek ve temizlemek ve zarif bir şekilde kapatmak en iyisi olabilir (çünkü kesintilere dayanmayan, iyi tasarlanmış uygulamanızın kullanıldığı için kesme sinyallerini almak bir şekilde tasarlanmamış ve bu yüzden bir şeyler yanlış olmalı). Alternatif olarak, söz konusu kod kritik olmayan veya önemsiz bir şeyse, kesmeyi görmezden gelmek (veya günlüğe kaydetmek) ve devam etmek isteyebilirsiniz.

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.