Sự khác biệt giữa trạng thái luồng WAIT và BLOCKED


101

Sự khác biệt giữa trạng thái luồng WAIT và trạng thái luồng BLOCKED là gì?

Các tài liệu Thread.State :

Bị chặn
Một luồng bị chặn đang chờ khóa màn hình ở trạng thái này.

Đang chờ
Một chuỗi đang chờ vô thời hạn cho một chuỗi khác thực hiện một hành động cụ thể ở trạng thái này

không giải thích sự khác biệt cho tôi.


kiểm tra câu trả lời trong chuỗi này stackoverflow.com/questions/2534147/java-thread-wait-blocked cũng như liên kết này có thể cung cấp thêm thông tin làm rõ geekexplains.blogspot.cz/2008/07/…
Abdul

@Abdul liên kết geekexplains nói rằng một luồng có thể chuyển sang trạng thái bị chặn bằng cách gọi Object.wait (), điều đó không chính xác phải không?
Hơn 5 giờ

theo oracle docs docs.oracle.com/javase/6/docs/api/java/lang/… : Một luồng đang ở trạng thái chờ do gọi một trong các phương thức sau: Object.wait mà không có thời gian chờ, Thread.join không có thời gian chờ, LockSupport.park
Abdul

Đối với hồ sơ, tôi nghĩ câu trả lời của @ Flavio tốt hơn một chút so với Ankit trong trường hợp bạn có thể cân nhắc thay đổi.
Xám

Câu trả lời:


80

Một luồng chuyển sang trạng thái chờ khi nó gọi wait()đến một Đối tượng. Đây được gọi là Trạng thái chờ đợi . Khi một luồng đạt đến trạng thái chờ, nó sẽ cần đợi cho đến khi một số luồng khác gọi notify()hoặc notifyAll()trên đối tượng.

Khi luồng này được thông báo, nó sẽ không thể chạy được. Có thể các luồng khác cũng được thông báo (đang sử dụng notifyAll()) hoặc luồng đầu tiên chưa hoàn thành công việc của mình, vì vậy nó vẫn bị chặn cho đến khi có cơ hội. Đây được gọi là Trạng thái bị chặn . Trạng thái Bị chặn sẽ xảy ra bất cứ khi nào một luồng cố gắng lấy khóa đối tượng và một số luồng khác đã giữ khóa.

Khi các luồng khác đã rời khỏi và cơ hội của luồng này, nó sẽ chuyển sang trạng thái Runnable sau đó đủ điều kiện nhận công việc dựa trên cơ chế phân luồng JVM và chuyển sang trạng thái chạy.


2
Bạn đã giải thích nó tốt hơn nhiều vì bạn đã giải thích trình tự trong đó một chuỗi đạt đến hai trạng thái đó, điều này làm cho nó rõ ràng hơn là chỉ giải thích từng trạng thái riêng lẻ (được thực hiện bởi câu trả lời của "More Than Five"
Kumar Manish

7
Đối với tất cả những người, những người thắc mắc tại sao hầu hết (tất cả?) Các biểu đồ trạng thái được tìm thấy trong xác nhận quyền sở hữu web, thông báo () / InformAll () dẫn đến RUNNABLE thay vì BLOCKED: stackoverflow.com/questions/28378592/…
Niklas Peter

Giả sử chỉ có một luồng và đợi trong một khoảng thời gian tính bằng mili; bây giờ Có thể một luồng có thể trực tiếp từ trạng thái chờ chuyển sang trạng thái có thể chạy được không? vì không có luồng nào khác bị khóa ở đây vì chỉ có một luồng?
Kanagavelu Sugumar

Có một phương thức đợi (thời gian) sẽ trở lại trạng thái có thể chạy sau khi thời gian trôi qua. Nhưng nếu không chỉ định thời gian, nó sẽ đợi cho đến khi luồng khác thông báo hoặc luồng bị gián đoạn.
Ankit Bansal

2
Câu trả lời của bạn là tốt nhưng nó không hoàn toàn giải thích rằng bạn có thể vào trạng thái Bị chặn bất cứ lúc nào bạn cố gắng lấy khóa. Nó không liên quan gì đến tín hiệu / thông báo.
Xám

90

Sự khác biệt là tương đối đơn giản.

Trong BLOCKEDtrạng thái, một luồng sắp đi vào một synchronizedkhối, nhưng có một luồng khác hiện đang chạy bên trong một synchronizedkhối trên cùng một đối tượng. Sau đó, luồng đầu tiên phải đợi luồng thứ hai thoát khỏi khối của nó.

Trong WAITINGtrạng thái, một luồng đang đợi tín hiệu từ một luồng khác. Điều này thường xảy ra bằng cách gọi Object.wait()hoặc Thread.join(). Sau đó luồng sẽ vẫn ở trạng thái này cho đến khi luồng khác gọi Object.notify()hoặc chết.


2
có chính xác không khi nói rằng chỉ bản thân một chuỗi mới có thể khiến nó chuyển sang trạng thái chờ? Thread-B có thể làm cho Thread-A chuyển sang trạng thái WAIT không?
Hơn 5 giờ

1
Bạn hiếm khi sử dụng Object.wait()trực tiếp, nhưng cuối cùng bạn cũng ở WAITINGtrạng thái sử dụng các cấu trúc đồng thời cấp cao hơn - như khóa, hàng đợi chặn, v.v., nói rộng ra, bất cứ khi nào hai luồng phải phối hợp.
Flavio

1
Từ kinh nghiệm cá nhân, các luồng đang chờ IO (ví dụ: đọc từ Socket) đang ở RUNNINGtrạng thái.
Flavio

4
Tài liệu Java8 cho Thread.Statebiết, "... Những trạng thái này là trạng thái máy ảo không phản ánh bất kỳ trạng thái luồng nào của hệ điều hành." Nói cách khác, JVM không quan tâm đến sự khác biệt giữa một tiểu trình đang chạy mã Java, một tiểu trình đang chờ lệnh gọi hệ thống trả về hoặc một tiểu trình đang chờ một lát thời gian. Đó là tất cả RUNNABLEnhững gì JVM có liên quan.
Solomon Slow vào

3
Có thể rất hay khi thêm rằng khi một luồng di chuyển từ WAITINGtrạng thái, trước tiên nó phải chuyển đến BLOCKEDtrạng thái cho đến khi nó có thể nhận được khóa được liên kết với đối tượng mà nó đang đợi.
Xám

21

Sự khác biệt quan trọng giữa trạng thái bị chặn và trạng thái chờ là tác động lên bộ lập lịch. Một chuỗi ở trạng thái bị chặn đang tranh giành một khóa; luồng đó vẫn được coi là thứ mà bộ lập lịch biểu cần phục vụ, có thể được tính vào quyết định của bộ lập lịch về khoảng thời gian để cung cấp cho các luồng đang chạy (để nó có thể tạo cơ hội cho các luồng chặn trên khóa).

Khi một luồng ở trạng thái chờ, áp lực mà nó gây ra trên hệ thống được giảm thiểu và người lập lịch trình không phải lo lắng về điều đó. Nó không hoạt động cho đến khi nhận được thông báo. Ngoại trừ thực tế là nó giữ một chuỗi hệ điều hành bị chiếm đóng, nó hoàn toàn không hoạt động.

Đây là lý do tại sao việc sử dụng InformAll ít lý tưởng hơn, nó khiến một loạt các chuỗi trước đó đã ngủ yên vui vẻ không tải lên hệ thống để được đánh thức, nơi hầu hết chúng sẽ chặn cho đến khi họ có thể nhận được khóa, tìm thấy tình trạng của chúng. chờ đợi là không đúng, và quay trở lại chờ đợi. Sẽ tốt hơn nếu chỉ thông báo cho những chủ đề có cơ hội đạt được tiến bộ.

(Sử dụng ReentrantLock thay vì khóa nội tại cho phép bạn có nhiều điều kiện cho một khóa, để bạn có thể đảm bảo rằng chuỗi được thông báo là một chuỗi đang chờ trong một điều kiện cụ thể, tránh lỗi thông báo bị mất trong trường hợp một chuỗi được thông báo cho thứ mà nó không thể hoạt động.)


Đó có phải là vì một số luồng khác có trách nhiệm gọi thông báo () trên đối tượng giám sát không?
berimbolo

@berimbolo: Tôi không hiểu những gì bạn đang yêu cầu
Nathan Hughes

Nó liên quan đến lý do tại sao một chuỗi chờ không phải là điều mà người lập lịch trình cần lo lắng. Tôi tự hỏi liệu đó có phải là do một luồng khác sẽ chịu trách nhiệm gọi thông báo nếu nó đang chờ.
berimbolo

@berimbolo: Chủ đề đang chờ cuối cùng cũng bị đánh thức bởi một thông báo. Bộ lập lịch sẽ quyết định chuỗi chờ nào được thông báo.
Nathan Hughes,

đếm một cái gì đó, bạn đang nói spin-lock, liều BLOCKED không có nghĩa là nó là spin-lock
Frank Zhang

16

Quan điểm đơn giản để diễn giải kết xuất chuỗi:

  • CHỜ - Tôi đang chờ được giao một số công việc, vì vậy tôi đang nhàn rỗi.
  • BỊ CHẶN - Tôi đang bận cố gắng hoàn thành công việc nhưng một chuỗi khác đang cản đường tôi, vì vậy tôi hiện đang rảnh.
  • RUNNABLE ... (Native Method) - Tôi đã gọi RUN một số mã gốc (chưa hoàn thành) theo như JVM có liên quan, bạn RUNNABLE và nó không thể cung cấp thêm bất kỳ thông tin nào. Một ví dụ phổ biến sẽ là một phương thức lắng nghe socket gốc được mã hóa bằng C, phương thức này thực sự đang đợi bất kỳ lưu lượng nào đến, vì vậy tôi đang rảnh rỗi ngay bây giờ. Trong tình huống đó, đây có thể được coi là một loại WAIT đặc biệt vì chúng tôi không thực sự CHẠY (không ghi CPU) nhưng bạn phải sử dụng kết xuất luồng OS thay vì kết xuất luồng Java để xem nó.

1
Tôi thích lời giải thích của bạn. Đó chính xác là những gì tôi đang cố gắng để làm trong chủ đề phân tích bãi ngay bây giờ :)
Sridhar Sarnobat

@MuhammadGelbana Vâng, bạn nói đúng, tôi đã xóa nhận xét.
Eric Wang

1
Của bạn RUNNABLEkhông hoàn toàn đúng. Nó có thể nằm trong hàng đợi chạy Java nhưng không thực thi hoặc nó có thể đang thực thi mã Java. Không nhất thiết phải gọi quê hương.
Xám

1

Bị chặn- Luồng của bạn đang ở trạng thái có thể chạy được trong vòng đời luồng và đang cố gắng lấy khóa đối tượng. Chờ- Luồng của bạn đang ở trạng thái chờ của vòng đời luồng và đợi tín hiệu thông báo đến ở trạng thái có thể chạy được của luồng.


-1

xem ví dụ này:

biểu diễn các trạng thái của luồng.

/*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();
        }
    }
}
}

Cảm ơn vì mã nhưng tôi muốn bạn có câu trả lời bằng văn bản và sau đó hiển thị một khối mã nhỏ .
Xám
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.