Apa artinya utas ini bergabung dengan kode?


156

Dalam kode ini, apa arti keduanya bergabung dan pecah? t1.join()menyebabkan t2berhenti sampai t1berakhir?

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
Karena itu akan memblokir dan menunggu penghentian utas, mengapa Anda menggunakan loop sementara?
Mehdi

@ MahdiElMasaoudi saya kira, untuk tetap menunggu bahkan jika utasnya terputus? Mungkin bukan cara yang bagus untuk melakukan itu
forresthopkinsa

Ingatlah untuk menerima jawaban di sini jika itu membantu.
Gray

Seperti yang disebutkan, Anda tidak perlu while(true)memanggil joinmetode.
Chaklader Asfak Arefe

Jawaban:


311

Apa artinya utas ini bergabung dengan kode?

Mengutip dari Thread.join()metode javadocs :

join() Menunggu utas ini mati.

Ada utas yang menjalankan kode contoh Anda yang mungkin merupakan utas utama .

  1. Utas utama membuat dan memulai utas t1dan t2utas. Kedua utas mulai berjalan secara paralel.
  2. Utas utama panggilan t1.join()untuk menunggu t1utas selesai.
  3. The t1benang selesai dan t1.join()kembali metode di thread utama. Catatan yang t1sudah bisa diselesaikan sebelum join()panggilan dibuat dalam hal join()panggilan akan segera kembali.
  4. Utas utama panggilan t2.join()untuk menunggu t2utas selesai.
  5. The t2Rampungkan benang (atau mungkin telah selesai sebelum t1benang lakukan) dan t2.join()metode kembali di thread utama.

Penting untuk memahami bahwa t1dan t2utas telah berjalan secara paralel tetapi utas utama yang memulai harus menunggu sampai selesai sebelum utas dapat berlanjut. Itu pola umum. Juga, t1dan / atau t2bisa selesai sebelum utas utama memanggil join()mereka. Jika demikian maka join()tidak akan menunggu tetapi akan segera kembali.

t1.join() berarti menyebabkan t2 berhenti sampai t1 berakhir?

Tidak. Utas utama yang memanggil t1.join()akan berhenti berjalan dan menunggu t1utas selesai. The t2benang berjalan secara paralel dan tidak terpengaruh oleh t1atau t1.join()panggilan sama sekali.

Dalam hal coba / tangkap, join()lemparan InterruptedExceptionberarti bahwa utas utama yang memanggil join()sendiri dapat terganggu oleh utas lainnya.

while (true) {

Bergabung dalam satu whilelingkaran adalah pola yang aneh. Biasanya Anda akan melakukan gabungan pertama dan kemudian gabungan kedua menangani dengan InterruptedExceptiontepat dalam setiap kasus. Tidak perlu menempatkan mereka dalam satu lingkaran.


24
+1 Itu pola yang sangat aneh dan mungkin bisa dihapus.
m0skit0

3
Jika t1 selesai dulu, maka t2 selesai. Itu tampaknya merupakan proses yang berurutan. Satu utas selesai pertama, lalu yang lainnya. apa gunanya multiple threading?
user697911

9
Karena itu t1dan t2dapat berjalan secara paralel. Hanya saja mainkebutuhan mereka berdua untuk selesai sebelum itu bisa berlanjut. Itu adalah pola khas @ user697911.
Gray

3
The whileloop di sana karena (saya kira) itu ingin mencoba kembali join()panggilan jika salah satu terganggu? Saya pasti tidak akan menulis seperti itu di @ user697911.
Gray

5
Loop ada untuk memastikan keduanya t1dan t2selesai. Yaitu. jika t1melempar InterruptedException, itu akan berulang dan menunggu t2. Alternatifnya adalah menunggu kedua utas di setiap Try-Catch mereka, sehingga perulangan dapat dihindari. Juga, tergantung pada EventThread, masuk akal untuk melakukannya dengan cara ini, karena kami menjalankan 2 utas, bukan satu.
Michael Bisbjerg

68

Ini adalah pertanyaan wawancara Jawa favorit .

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()berarti, t1 mengatakan sesuatu seperti " Saya ingin menyelesaikan dulu ". Sama halnya dengan t2. Tidak peduli siapa yang memulai t1atau t2utas (dalam hal ini mainmetode), utama akan menunggu sampai t1dan t2menyelesaikan tugas mereka.

Namun, poin penting untuk mencatat, t1dan t2diri mereka sendiri dapat dijalankan secara paralel terlepas dari bergabung urutan panggilan pada t1dan t2. Ini adalah main/daemonbenang yang harus menunggu .


3
Contoh yang baik. Tentang "bisa berjalan secara paralel": Jadi apa? Adalah penting bahwa utas utama akan menunggu PERTAMA untuk t1 dan LALU untuk t2. Tidak masalah apa yang dilakukan t1 atau t2 (dari perspektif utas)
Alex

1
Anda menyebutkan utas "main / daemon". Utama saya mengerti tetapi dasmon tidak ada hubungannya dengan itu. Utas utama adalah non-daemon.
Gray

1
t1.join(); t2.join();tidak akan mengizinkan utas yang mengeksekusi gabungan terus sampai kedua utas telah berakhir. Dengan tidak adanya kode yang sangat tidak biasa di tempat lain, urutan bergabung tidak menjadi masalah.
David Schwartz

Jadi t2.join () akan dipanggil hanya ketika t1 selesai?
Leo Droidcoder

Dengan kata lain, jika kita ingin "membuat serial" pelaksanaan utas t1 dan t2, kita perlu menempatkan t1.join () tepat setelah t1.start () karena utas utama mulai t1 (dan t2 sesudahnya) dan tentu saja menghapusnya dari coba tangkap. Jelas, dengan melakukan itu, konsekuensinya adalah hilangnya paralelisme.
dobrivoje

47

join()berarti menunggu utas selesai. Ini adalah metode pemblokir. Utas utama Anda (yang menjalankan join()) akan menunggu di t1.join()telepon sampai t1selesai, dan kemudian akan melakukan hal yang sama t2.join().


29

Sebuah gambar bernilai ribuan kata.

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

Semoga bermanfaat, untuk lebih detail klik di sini


3
Jelas dan tepat.
dobrivoje

10

Ketika utas tA memanggil tB.join (), penyebabnya tidak hanya menunggu tB untuk mati atau tA terputus, tetapi juga membuat hubungan sebelum-kejadian antara pernyataan terakhir di tB dan pernyataan berikutnya setelah tB.join () di utas tA.

Semua tindakan di utas terjadi sebelum utas lain berhasil kembali dari gabungan () di utas itu.

Itu berarti 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();

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

Selalu cetak

>> 1111111111111111111111111 ...

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

Dapat mencetak tidak hanya

>> 0000000000 ... 000000111111111111111111111111 ...

Tapi

>> 00000000000000000000000000000000000000000000 ... 

Selalu hanya '0'.

Karena Java Memory Model tidak memerlukan 'mentransfer' nilai baru 'sharedVar' dari threadB ke utas tanpa heppens-sebelum relasi (permulaan thread, penggabungan thread, penggunaan kata kunci 'synchonized', penggunaan variabel AtomicXXX, dll).


5

Sederhananya:
t1.join()pengembalian setelah t1selesai.
Itu tidak melakukan apa pun untuk utas t1, kecuali menunggu sampai selesai.
Secara alami, kode berikut t1.join()akan dieksekusi hanya setelah t1.join()pengembalian.


1
akan dieksekusi hanya setelah t1.join () mengembalikan +1
mohsen.nour

3

Dari halaman dokumentasi oracle pada Bergabung

The joinMetode memungkinkan satu thread untuk menunggu selesainya lain.

Jika t1 adalah Threadobjek yang utangnya sedang dieksekusi,

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

Jika t2 adalah Threadobjek yang utangnya sedang dieksekusi,

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

joinAPI adalah API level rendah, yang telah diperkenalkan di versi java sebelumnya. Banyak hal telah diubah selama periode waktu tertentu (terutama dengan rilis jdk 1.5) di depan concurrency.

Anda dapat mencapai hal yang sama dengan java.util.concurrent API. Beberapa contohnya adalah

  1. Gunakan invokeAll onExecutorService
  2. Menggunakan CountDownLatch
  3. Menggunakan ForkJoinPool atau newWorkStealingPool dari Executors(sejak java 8)

Lihat pertanyaan SE terkait:

tunggu sampai semua utas menyelesaikan pekerjaan mereka di java


1

Bagi saya, perilaku Join () selalu membingungkan karena saya mencoba mengingat siapa yang akan menunggu siapa. Jangan mencoba mengingatnya seperti itu.

Di bawahnya, itu murni mekanisme wait () dan notify ().

Kita semua tahu bahwa, ketika kita memanggil wait () pada objek apa pun (t1), objek panggilan (utama) dikirim ke ruang tunggu (status Blocked).

Di sini, utas utama adalah panggilan bergabung () yang menunggu () di bawah selimut. Jadi utas utama akan menunggu sampai diberitahukan. Pemberitahuan diberikan oleh t1 ketika selesai dijalankan (utas selesai).

Setelah menerima notifikasi, main keluar dari ruang tunggu dan melanjutkan eksekusi.


0

Semoga ini bisa membantu!

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

katakanlah utas utama kami memulai utas t1 dan t2. Sekarang, ketika t1.join () dipanggil, utas utama menangguhkan dirinya sendiri hingga utas t1 mati dan kemudian melanjutkan kembali. Demikian pula, ketika t2.join () dijalankan, utas utama ditangguhkan lagi sampai utas t2 mati dan kemudian dilanjutkan.

Jadi, ini cara kerjanya.

Juga, loop sementara tidak benar-benar diperlukan di sini.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.