Perbedaan antara status thread WAIT dan BLOCKED


101

Apa perbedaan antara status thread WAIT dan status thread BLOCKED?

The Thread.State dokumentasi :

Diblokir
Utas yang diblokir menunggu kunci monitor berada dalam status ini.

Menunggu
Sebuah thread yang menunggu tanpa batas waktu thread lain untuk melakukan tindakan tertentu berada dalam status ini

tidak menjelaskan perbedaannya kepada saya.


periksa jawaban di utas ini stackoverflow.com/questions/2534147/java-thread-wait-blocked juga tautan ini dapat memberikan klarifikasi lebih lanjut geekexplains.blogspot.cz/2008/07/…
Abdul

@Abdul tautan geekexplains mengatakan bahwa utas dapat masuk ke status diblokir dengan memanggil Object.wait () yang tidak benar, bukan?
Lebih dari Lima

menurut oracle docs docs.oracle.com/javase/6/docs/api/java/lang/… : Sebuah utas dalam keadaan menunggu karena memanggil salah satu metode berikut: Object.wait tanpa batas waktu, Thread.join tanpa batas waktu, LockSupport.park
Abdul

Sebagai catatan, saya pikir jawaban @ Flavio sedikit lebih baik daripada jawaban Ankit jika Anda mungkin mempertimbangkan untuk mengubahnya.
Gray

Jawaban:


80

Sebuah utas akan menunggu status setelah memanggil wait()Objek. Ini disebut Status Menunggu . Setelah utas mencapai status menunggu, utas harus menunggu hingga utas lain memanggil notify()atau notifyAll()pada objek.

Setelah utas ini diberi tahu, utas tidak akan dapat dijalankan. Bisa jadi utas lain juga diberitahukan (menggunakan notifyAll()) atau utas pertama belum menyelesaikan pekerjaannya, sehingga masih diblokir sampai mendapat kesempatan. Ini disebut Status Diblokir . Keadaan diblokir akan terjadi setiap kali utas mencoba untuk mendapatkan kunci pada objek dan beberapa utas lain sudah menahan kunci.

Setelah utas lain keluar dan utas ini berpeluang, utas tersebut pindah ke status Runnable setelah itu memenuhi syarat pekerjaan pengambilan berdasarkan mekanisme threading JVM dan pindah ke status berjalan.


2
Anda menjelaskannya jauh lebih baik karena Anda menjelaskan urutan utas mencapai dua kondisi tersebut yang membuatnya lebih jelas daripada hanya menjelaskan masing-masing dari dua kondisi secara terpisah (yang dilakukan oleh jawaban "Lebih dari Lima"
Kumar Manish

7
Untuk semua itu, siapa yang bertanya-tanya mengapa sebagian besar (semua?) Dari diagram status yang ditemukan di klaim web, yang notify () / notifyAll () menghasilkan RUNNABLE daripada BLOCKED: stackoverflow.com/questions/28378592/…
Niklas Peter

Asumsikan hanya ada satu utas dan menunggu beberapa waktu dalam milidetik; sekarang Apakah mungkin utas dapat langsung dari status menunggu untuk masuk ke status runnable? karena tidak ada utas lain yang mengunci di sini karena hanya utas tunggal?
Kanagavelu Sugumar

Ada metode menunggu (waktu) yang akan kembali ke status runnable setelah waktu berlalu. Tetapi jika tidak ada waktu yang ditentukan, itu akan menunggu sampai utas lain memberi tahu atau utas terputus.
Ankit Bansal

2
Jawaban Anda bagus tetapi tidak cukup menjelaskan bahwa Anda dapat memasuki keadaan Diblokir kapan pun Anda mencoba untuk mendapatkan kunci. Itu tidak ada hubungannya dengan signal / notify.
Gray

90

Perbedaannya relatif sederhana.

Dalam BLOCKEDstatus, utas akan memasuki synchronizedblok, tetapi ada utas lain yang sedang berjalan di dalam synchronizedblok pada objek yang sama. Utas pertama kemudian harus menunggu utas kedua keluar dari bloknya.

Dalam WAITINGstatus, utas sedang menunggu sinyal dari utas lain. Ini biasanya terjadi dengan menelepon Object.wait(), atau Thread.join(). Utas kemudian akan tetap dalam keadaan ini sampai utas lain memanggil Object.notify(), atau mati.


2
apakah benar untuk mengatakan bahwa hanya utas itu sendiri yang dapat membuatnya menunggu? Bisakah Thread-B membuat Thread-A menjadi status WAIT?
Lebih dari Lima

1
Anda jarang menggunakan Object.wait()secara langsung, tetapi Anda berakhir di WAITINGstatus tersebut juga menggunakan konstruksi konkurensi tingkat tinggi - seperti kunci, antrean pemblokiran, dll ... secara umum, setiap kali dua utas harus berkoordinasi.
Flavio

1
Dari pengalaman pribadi, utas menunggu IO (misalnya membaca dari Socket) berada dalam RUNNINGstatus.
Flavio

4
Dokumen Java8 untuk Thread.Statemengatakan, "... Status ini adalah status mesin virtual yang tidak mencerminkan status thread sistem operasi apa pun." Dengan kata lain, JVM tidak peduli tentang perbedaan antara utas yang menjalankan kode Java, utas yang menunggu panggilan sistem untuk kembali, atau utas yang menunggu potongan waktu. Itu semua hanya RUNNABLEsejauh menyangkut JVM.
Solomon Slow

3
Mungkin bagus untuk menambahkan bahwa ketika utas berpindah dari WAITINGstatus, utas harus terlebih dahulu masuk ke BLOCKEDstatus hingga dapat memperoleh kunci yang terkait dengan objek yang ditunggunya.
Gray

22

Perbedaan penting antara status diblokir dan menunggu adalah dampaknya pada penjadwal. Sebuah utas dalam keadaan diblokir bersaing untuk mendapatkan kunci; utas itu masih dihitung sebagai sesuatu yang perlu diservis oleh penjadwal, mungkin diperhitungkan dalam keputusan penjadwal tentang berapa banyak waktu untuk memberikan utas yang berjalan (sehingga dapat memberi kesempatan utas memblokir pada kunci).

Setelah utas berada dalam status tunggu, tekanan yang diberikan pada sistem diminimalkan, dan penjadwal tidak perlu mengkhawatirkannya. Ini tidak aktif sampai menerima pemberitahuan. Kecuali fakta bahwa itu membuat utas OS terisi, itu sepenuhnya keluar dari permainan.

Inilah sebabnya mengapa menggunakan notifyAll kurang dari ideal, itu menyebabkan sekelompok utas yang sebelumnya dengan senang hati tidak aktif sehingga tidak membebani sistem menjadi terbangun, di mana kebanyakan dari mereka akan memblokir sampai mereka dapat memperoleh kunci, menemukan kondisinya. menunggu tidak benar, dan kembali menunggu. Akan lebih baik jika memberi tahu hanya utas yang memiliki peluang untuk membuat kemajuan.

(Menggunakan ReentrantLock alih-alih kunci intrinsik memungkinkan Anda memiliki beberapa ketentuan untuk satu kunci, sehingga Anda dapat memastikan utas yang diberi tahu adalah utas yang menunggu pada kondisi tertentu, menghindari bug pemberitahuan hilang jika utas mendapat pemberitahuan untuk sesuatu yang tidak bisa ditindaklanjuti.)


Apakah karena itu adalah tanggung jawab utas lain untuk memanggil notify () pada objek monitor?
berimbolo

@berimbolo: Saya tidak mengerti apa yang Anda tanyakan
Nathan Hughes

Itu berkaitan dengan mengapa utas menunggu bukanlah sesuatu yang perlu dikhawatirkan oleh penjadwal. Saya bertanya-tanya apakah itu karena utas lain akan bertanggung jawab untuk menelepon beri tahu jika menunggu.
berimbolo

@berimbolo: Thread yang menunggu akhirnya dibangunkan oleh notify. Penjadwal akan memutuskan utas tunggu mana yang akan diberi tahu.
Nathan Hughes

menghitung sesuatu, Anda mengatakan spin-lock, dosis DIBLOKIR bukan berarti itu spin-lock
Frank Zhang

16

Perspektif yang disederhanakan untuk menafsirkan thread dump:

  • TUNGGU - Saya menunggu untuk diberi pekerjaan, jadi saya menganggur sekarang.
  • DIBLOKIR - Saya sibuk mencoba menyelesaikan pekerjaan tetapi utas lain menghalangi jalan saya, jadi saya menganggur sekarang.
  • DAPAT DIJALANKAN ... (Metode Asli) - Saya memanggil untuk MENJALANKAN beberapa kode asli (yang belum selesai) sejauh menyangkut JVM, Anda DAPAT DIJALANKAN dan tidak dapat memberikan informasi lebih lanjut. Contoh umum adalah metode pendengar soket asli yang dikodekan dalam C yang sebenarnya menunggu lalu lintas datang, jadi saya menganggur sekarang. Dalam situasi itu, ini dapat dilihat sebagai jenis TUNGGU khusus karena kami sebenarnya tidak MENJALANKAN (tidak ada CPU yang terbakar) sama sekali tetapi Anda harus menggunakan dump thread OS daripada dump thread Java untuk melihatnya.

1
Saya suka penjelasan Anda. Itulah yang saya coba lakukan dalam menganalisis thread dumps sekarang :)
Sridhar Sarnobat

@MuhammadGelbana Ya, Anda benar, komentarnya sudah saya hapus.
Eric Wang

1
Anda RUNNABLEkurang tepat. Ini bisa berada dalam antrian run Java tetapi tidak mengeksekusi atau bisa juga menjalankan kode Java. Itu tidak harus memanggil ke tanah air.
Gray

1

Diblokir- Utas Anda dalam keadaan siklus hidup utas yang dapat dijalankan dan mencoba mendapatkan kunci objek. Tunggu- Utas Anda dalam keadaan menunggu siklus hidup utas dan menunggu sinyal pemberitahuan datang dalam keadaan utas yang dapat dijalankan.


-1

lihat contoh ini:

demonstrasi status utas.

/*NEW- thread object created, but not started.
RUNNABLE- thread is executing.
BLOCKED- waiting for monitor after calling wait() method.
WAITING- when wait() if called & waiting for notify() to be called.
  Also when join() is called.
TIMED_WAITING- when below methods are called:
 Thread.sleep
 Object.wait with timeout
 Thread.join with timeout
TERMINATED- thread returned from run() method.*/
public class ThreadBlockingState{

public static void main(String[] args) throws InterruptedException {
    Object obj= new Object();
    Object obj2 = new Object();
    Thread3 t3 = new Thread3(obj,obj2);
    Thread.sleep(1000);
    System.out.println("nm:"+t3.getName()+",state:"+t3.getState().toString()+
            ",when Wait() is called & waiting for notify() to be called.");
    Thread4 t4 = new Thread4(obj,obj2);
    Thread.sleep(3000);
    System.out.println("nm:"+t3.getName()+",state:"+t3.getState().toString()+",After calling Wait() & waiting for monitor of obj2.");
    System.out.println("nm:"+t4.getName()+",state:"+t4.getState().toString()+",when sleep() is called.");
}

}
class Thread3 extends Thread{
Object obj,obj2;
int cnt;
Thread3(Object obj,Object obj2){
    this.obj = obj;
    this.obj2 = obj2;
    this.start();
}

@Override
public void run() {
    super.run();
    synchronized (obj) {
        try {
            System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",Before Wait().");
            obj.wait();             
            System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",After Wait().");
            synchronized (obj2) {
                cnt++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}
class Thread4 extends Thread{
Object obj,obj2;
Thread4(Object obj,Object obj2){
    this.obj = obj;
    this.obj2 = obj2;
    this.start();
}

@Override
public void run() {
    super.run();
    synchronized (obj) {
        System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",Before notify().");
        obj.notify();
        System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",After notify().");
    }
    synchronized (obj2) {
        try {
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}

Terima kasih untuk kodenya tetapi saya lebih suka Anda memiliki jawaban tekstual dan kemudian menunjukkan blok kode kecil .
Gray
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.