Bu iş parçacığı birleştirme kodu ne anlama geliyor?


156

Bu kodda, iki birleşim ve kopma ne anlama geliyor? sona erene kadar durma t1.join()nedenleri ?t2t1

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread t2 = new Thread(new EventThread("e2"));
t2.start();
while (true) {
   try {
      t1.join();
      t2.join();
      break;
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}


3
İş parçacığı sonlandırmasını engelleyip bekleyeceğinden, neden while döngüsünü kullandınız?
Mehdi

@MahdiElMasaoudi Sanırım, iplik kesilse bile beklemeye devam etmek için? Muhtemelen bunu yapmanın harika bir yolu değil
forresthopkinsa

Yararlıysa, burada bir yanıtı kabul etmeyi unutmayın.
Gri

Belirtildiği gibi while(true), joinyöntemi çağırmanız gerekmez .
Chaklader Asfak Arefe

Yanıtlar:


311

Bu iş parçacığı birleştirme kodu ne anlama geliyor?

Dan alıntı Thread.join()yöntem javadocs :

join() Bu ipliğin ölmesini bekler.

Muhtemelen ana iş parçacığı olan örnek kodunuzu çalıştıran bir iş parçacığı vardır .

  1. Ana iş parçacığı oluşturur ve başlatır t1ve t2konuları. İki iplik paralel olarak çalışmaya başlar.
  2. Ana iş parçacığı t1.join(), t1iş parçacığının bitmesini beklemek için çağırır .
  3. İş t1parçacığı tamamlanır ve t1.join()yöntem ana iş parçacığında döner. Çağrı yapılmadan t1önce bitmiş olabileceğini unutmayın; join()bu durumda join()çağrı hemen geri döner.
  4. Ana iş parçacığı t2.join(), t2iş parçacığının bitmesini beklemek için çağırır .
  5. İş t2parçacığı tamamlanır (veya iş parçacığı tamamlanmadan önce tamamlanmış olabilir t1) ve t2.join()yöntem ana iş parçacığında geri döner.

t1Ve t2iş parçacıklarının paralel çalıştığını anlamak önemlidir, ancak onları başlatan ana iş parçacığının devam etmeden önce bitirmelerini beklemeleri gerekir. Bu yaygın bir örüntü. Ayrıca t1ve / veya ana iş parçacığı onları t2çağırmadan önce bitirmiş olabilir join(). Eğer öyleyse o join()zaman beklemeyecek ama hemen geri dönecektir.

t1.join() t1 sona erene kadar t2'nin durmasına neden olur?

Hayır. Arayan ana iş parçacığı t1.join()çalışmayı durdurur ve t1iş parçacığının bitmesini bekler . İş t2parçacığı paralel olarak çalışıyor ve çağrıdan t1veya t1.join()çağrıdan etkilenmiyor .

Try / catch açısından, join()atar InterruptedExceptionçağırıyor ana iş parçacığı anlamına join()may kendisini başka bir iş parçacığı tarafından kesilebilir.

while (true) {

Birleşimlerin bir whiledöngü içinde olması garip bir kalıptır. Tipik olarak InterruptedExceptionher durumda uygun bir şekilde işleyen ilk birleştirmeyi ve sonra ikinci birleştirmeyi yaparsınız . Onları bir döngüye sokmaya gerek yok.


24
+1 Bu çok garip bir desen ve muhtemelen kaldırılabilir.
m0skit0

3
Önce t1 biterse, bitirmek için t2. Bu ardışık bir süreç gibi görünüyor. Önce bir iplik, sonra diğeri biter. Çoklu diş açmanın anlamı nedir?
user697911

9
Çünkü t1ve t2paralel olarak çalışabilir. Sadece maindevam edebilmeleri için her ikisinin de bitirmesi gerekiyor. Bu tipik bir model @ user697911.
Gri

3
while(Sanırım) o yeniden denemek istediği için döngü vardır join()biri kesilirse aramaları? Kesinlikle bu şekilde yazmazdım @ user697911.
Gri

5
Döngü hem sağlamak için vardır t1ve t2bitiş. Yani. eğer t1atar InterruptedException, onun için en başa döner ve bekleme olacak t2. Bir alternatif, Try-Catch'larının her birinde her iki iş parçacığını beklemektir, böylece döngü önlenebilir. Ayrıca, bağlı olarak EventThread, bu şekilde yapmak mantıklı olabilir, çünkü bir değil 2 iplik çalıştırıyoruz.
Michael Bisbjerg

68

Bu favori bir Java röportaj sorusudur.

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread e2 = new Thread(new EventThread("e2"));
t2.start();

while (true) {
    try {
        t1.join(); // 1
        t2.join(); // 2  These lines (1,2) are in in public static void main
        break;
    }
}

t1.join()yani, t1 " Önce bitirmek istiyorum" gibi bir şey söylüyor . Aynı durum t2. Ne olursa olsun kimin başlattığını t1veya t2(bu durumda iplik mainyöntemi), ana dek bekleyecek t1ve t2görevlerini bitirmek.

Ancak, önemli bir nokta not etmek, t1ve t2kendileri bakılmaksızın paralel olarak çalıştırmak çağrı dizisi katılabilir üzerinde t1ve t2. Beklemek zorunda olan main/daemoniş parçacığıdır .


3
İyi örnek. Hakkında "paralel koşabilir": Ne olmuş yani? Ana iş parçacığının t1 için İLK ve SONRA t2 için beklemesi önemlidir. T1 veya t2'nin ne yaptığı önemli değil (ana iplik perspektifinden)
Alex

1
"Main / daemon" iş parçacığından bahsediyorsunuz. Anladığım ana şey ama arka plan programının bununla hiçbir ilgisi yok. Ana iş parçacığı daemon değil.
Gri

1
t1.join(); t2.join();her iki iş parçacığı sonlanıncaya kadar birleşimleri yürüten iş parçacığının devam etmesine izin vermez. Başka bir yerde çok sıradışı bir kodun bulunmadığı durumlarda, birleşimlerin sırası önemli değildir.
David Schwartz

Yani t2.join () sadece t1 bittiğinde çağrılır mı?
Leo Droidcoder

Başka bir deyişle, t1 ve t2 iş parçacıklarının yürütülmesini "serileştirmek" istiyorsak, ana iş parçacığı t1 (ve daha sonra t2) başladığından t1.start () 'dan hemen sonra t1.join ()' i yerleştirip elbette denemek / catch. Açıkçası, bunu yaparsanız, sonuç paralellik kaybı olacaktır.
dobrivoje

47

join()bir iş parçacığının tamamlanmasını beklemek anlamına gelir. Bu bir engelleyici yöntemdir. Ana iş parçanız (bunu yapan join()) işini t1.join()bitirene kadar hatta bekler t1ve sonra da aynısını yapar t2.join().


29

Bir resim bin kelime değerinde bir olup.

    Main thread-->----->--->-->--block##########continue--->---->
                 \                 |               |
sub thread start()\                | join()        |
                   \               |               |
                    ---sub thread----->--->--->--finish    

Faydalı olmak dileğiyle, daha fazla ayrıntı için buraya tıklayın


3
Açık ve kesin.
dobrivoje

10

TA çağrısı tB.join () çağrısının nedenleri, yalnızca tB'nin ölmesini beklemekle kalmaz veya tA kendi kendine kesilmez, aynı zamanda tB'deki son ifade ile tA iş parçacığında tB.join () öğesinden sonraki bir sonraki ifade arasında gerçekleşir.

Bir iş parçacığındaki tüm eylemler, başka bir iş parçacığı o iş parçasındaki bir join () öğesinden başarıyla geri dönmeden önce gerçekleşir.

Program demek

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        threadB.join();

        while (true) 
            System.out.print(sharedVar);
    }
}

Her zaman yazdır

>> 1111111111111111111111111 ...

Ama program

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        // threadB.join();  COMMENT JOIN

        while (true)
            System.out.print(sharedVar);
    }
}

Sadece yazdırabilir

>> 0000000000 ... 000000111111111111111111111111 ...

Fakat

>> 00000000000000000000000000000000000000000000 ... 

Her zaman sadece '0'.

Java Bellek Modeli, `` sharedVar '' ın yeni değerinin, ileti dizisinden önceki iş parçacığı olmadan ana iş parçacığına 'aktarılmasını gerektirmez (iş parçacığı başlatma, iş parçacığı birleşimi,' eşzamanlı 'anahtar sözcük kullanımı, AtomicXXX değişkenlerinin kullanımı, vb.).


5

Basitçe söylemek gerekirse:
t1.join()İade t1tamamlandıktan sonra döner .
İpliğin t1bitmesini beklemek dışında hiçbir şey yapmaz .
Doğal olarak, aşağıdaki kod t1.join()ancak iadelerden sonra yürütülecektir t1.join().


1
yalnızca t1.join () +1 döndürdükten sonra yürütülür
mohsen.nour

3

Katılanlar üzerindeki oracle dokümantasyon sayfasından

joinYöntem bir iplik bir tamamlanmasını beklemek sağlar.

T1, Threadiş parçacığı yürütülmekte olan bir nesne ise,

t1.join() : causes the current thread to pause execution until t1's thread terminates.

T2, Threadiş parçacığı yürütülmekte olan bir nesne ise,

t2.join(); causes the current thread to pause execution until t2's thread terminates.

joinAPI, java'nın önceki sürümlerinde tanıtılan düşük düzeyli API'dir. Eşzamanlılık cephesinde belirli bir süre (özellikle jdk 1.5 sürümünde) birçok şey değişti.

Aynısını java.util.concurrent API ile elde edebilirsiniz. Bazı örnekler

  1. İnvokeAll özelliğini kullanmaExecutorService
  2. CountDownLatch kullanma
  3. ForkJoinPool veya newWorkStealingPool of kullanma Executors(java 8'den beri)

İlgili SE sorularına bakın:

tüm iş parçacığı java çalışmalarını bitirmek


1

Benim için Join () davranışı her zaman kafa karıştırıcıydı çünkü kimin kimin bekleyeceğini hatırlamaya çalışıyordum. Bunu bu şekilde hatırlamaya çalışmayın.

Altında, saf wait () ve notify () mekanizmasıdır.

Hepimiz biliyoruz ki, herhangi bir nesne (t1) üzerinde wait () öğesini çağırdığımızda, çağrı nesnesi (main) bekleme odasına (Engellenen durum) gönderilir.

Burada, ana iş parçacığı altında wait () olan join () çağırıyor. Böylece ana iş parçacığı bildirilene kadar bekleyecektir. Bildirim, çalışmasını bitirdiğinde t1 tarafından verilir (iş parçacığı tamamlama).

Bildirimi aldıktan sonra, ana bekleme odasından çıkar ve yürütme işlemine devam eder.


0

Umarım yardımcı olur!

package join;

public class ThreadJoinApp {

    Thread th = new Thread("Thread 1") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());
            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    Thread th2 = new Thread("Thread 2") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());

            //Thread 2 waits until the thread 1 successfully completes.
            try {
            th.join();
            } catch( InterruptedException ex) {
                System.out.println("Exception has been caught");
            }

            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    public static void main(String[] args) {
        ThreadJoinApp threadJoinApp = new ThreadJoinApp();
        threadJoinApp.th.start();
        threadJoinApp.th2.start();
    }

    //Happy coding -- Parthasarathy S
}

-3

diyelim ki ana iş parçacığımız t1 ve t2 ipliklerini başlatıyor. Şimdi, t1.join () çağrıldığında, ana iplik t1 teli ölünceye kadar kendini askıya alır ve sonra kendini sürdürür. Benzer şekilde, t2.join () yürütüldüğünde, ana iplik t2 ipliği ölene ve devam edene kadar kendini yeniden askıya alır.

İşte böyle çalışır.

Ayrıca while döngüsü burada gerçekten gerekli değildi.

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.