Різниця між станами потоку WAIT і BLOCKED


101

Яка різниця між станом потоку ЗАЧЕКАЙТЕ і станом потоку БЛОКОВАНО?

Документація щодо теми :

Заблоковано
Нитка, яка заблокована в очікуванні блокування монітора, знаходиться в такому стані.

Очікування
Нитка, яка чекає нескінченно часу, щоб інша нитка виконала певну дію, знаходиться в цьому стані

не пояснює мені різниці.


перевірити відповідь у цій темі stackoverflow.com/questions/2534147/java-thread-wait-blocked також це посилання може дати додаткове уточнення geekexplains.blogspot.cz/2008/07/…
Abdul

@Abdul посилання geekexplains говорить, що потік може перейти в заблокований стан, зателефонувавши Object.wait (), що невірно, чи не так?
Більше ніж п'ять

відповідно до oracle docs docs.oracle.com/javase/6/docs/api/java/lang/… : Нитка перебуває в стані очікування завдяки виклику одного з наступних методів: Object.wait без таймауту, Thread.join без перерви, LockSupport.park
Абдул

Для запису, я думаю, що відповідь @ Флавіо трохи краща, ніж Анкіт у випадку, якщо ви можете розглянути можливість зміни.
Сірий

Відповіді:


80

Нитка переходить у стан очікування, коли вона викликає wait()Об'єкт. Це називається держава очікування . Як тільки нитка досягне стану очікування, їй потрібно буде зачекати, доки інший потік дзвонить notify()або notifyAll()на об'єкт.

Після повідомлення про цю нитку вона не підлягає застосуванню. Можливо, про інші потоки також повідомляється (використовується notifyAll()) або перший потік не закінчив свою роботу, тому він все ще блокується, поки не отримає свій шанс. Це називається Заблокований стан. Блокований стан буде виникати, коли нитка намагається придбати замок на об'єкті, а якийсь інший потік вже тримає замок.

Після того, як інші потоки залишилися і вона має шанс цього потоку, вона переходить у стан Runnable, після чого вона може підібрати роботу на основі механізму різьблення JVM і переходить у стан запуску.


2
Ви пояснили це набагато краще, тому що ви пояснили послідовність, у якій нитка досягає тих двох станів, що робить це зрозумілішим, ніж просто пояснення кожного з двох станів у відриві (що робиться за допомогою відповіді "Більше п’яти"
Кумар Маніш

7
Для всіх, хто цікавиться, чому більшість (усі?) Діаграм стану, знайдених в Інтернеті, стверджують, що notify () / notifyAll () призводить до RUNNABLE замість BLOCKED: stackoverflow.com/questions/28378592/…
Niklas Peter

Припустимо, є лише одна нитка і деякий час чекали в мілісах; тепер Чи можливо, що потік може безпосередньо із стану очікування перейти до стану, який можна виконати? оскільки жодна інша нитка не замикається тут, оскільки лише одна різьба?
Канагавелу Сугумар

Існує метод очікування (час), який повернеться до стану, який можна виконати, коли пройде час. Але якщо часу не вказано, він зачекає, поки інший потік сповістить або потік буде перервано.
Анкіт Бансал

2
Ваша відповідь хороша, але це не зовсім пояснює, що ви можете перейти в заблокований стан у будь-який час, намагаючись придбати блокування. Це не має нічого спільного з сигналом / сповіщенням.
Сірий

90

Різниця порівняно проста.

У BLOCKEDстані нитка збирається ввести synchronizedблок, але всередині іншої потоки працює інший потікsynchronized блоку того ж об'єкта. Перший потік повинен зачекати, поки другий потік вийде з його блоку.

У WAITINGстані нитка чекає сигналу від іншої нитки. Зазвичай це відбувається за допомогою дзвінка Object.wait(), або Thread.join(). Потім потік залишатиметься в такому стані, поки інший потік не викликає Object.notify()або не відмирає.


2
чи правильно сказати, що тільки нитка сама по собі може змусити її зачекати? Чи може Thread-B коли-небудь змусити Thread-A перейти до стану ЗАЧЕКАЙТЕ?
Більше ніж п'ять

1
Ви рідко використовуєте Object.wait()безпосередньо, але ви, в кінцевому підсумку, перебуваєте в WAITINGштаті, також використовуючи більш високорівневі конструкції одночасності - наприклад, блокування, блокування черг тощо ... загалом кажучи, коли два потоки мають узгоджуватись.
Флавіо

1
З особистого досвіду теми, які чекають IO (наприклад, читання з Socket), знаходяться в RUNNINGстані.
Флавіо

4
Java8 doc для Thread.Stateкаже: "... Ці стани - це стан віртуальної машини, який не відображає жодного стану потоку операційної системи". Іншими словами, JVM не піклується про різницю між потоком, на якому працює код Java, потоком, який чекає повернення системного дзвінка, або потоком, який чекає часового відрізка. Це все так RUNNABLEсамо, що стосується СВМ.
Соломон повільно

3
Було б непогано додати, що коли потік переміщується зі WAITINGстану, він спочатку повинен перейти до BLOCKEDстану, поки він не зможе придбати замок, пов’язаний з об'єктом, на який він чекав.
Сірий

22

Важлива відмінність заблокованого стану та стану очікування - це вплив на планувальник. Нитка в заблокованому стані претендує на замок; цей потік все ще вважається чимось, що планувальник повинен обслуговувати, можливо, враховуючи рішення планувальника про те, скільки часу надавати запущеним потокам (щоб він міг дати шанс блокування потоків на блоці).

Після того, як нитка перебуває в стані очікування, напруга, яку вона надає системі, зводиться до мінімуму, і планувальникові не потрібно про це турбуватися. Він перебуває в спокої, поки не отримає повідомлення. За винятком того, що він тримає нитку ОС зайнятою, вона повністю не грає.

Ось чому використання notifyAll є менш ніж ідеальним, це призводить до того, що низка потоків, які раніше були щасливо дрімаючими, не ставлячи навантаження на систему, щоб прокинутися, де більшість із них заблокує, поки вони не зможуть придбати замок, знайти стан, у якому вони є чекати неправда, і повернутися до очікування. Бажано повідомити лише ті теми, які мають шанс прогресувати.

(Використання ReentrantLock замість внутрішніх блокувань дозволяє вам мати кілька умов для одного блокування, так що ви можете переконатися, що сповіщена нитка є такою, яка чекає за певної умови, уникаючи помилки втраченого сповіщення у випадку отримання потоком повідомлень про щось, на що не може діяти.)


Це тому, що це відповідальність за виклик notify () на об'єкт монітора?
berimbolo

@berimbolo: Я не розумію, про що ви питаєте
Nathan Hughes

Це стосувалося того, чому чекання потоку - це не те, про що планують планувати. Мені було цікаво, чи це тому, що інша нитка буде відповідати за виклик сповіщення, якщо він чекає.
berimbolo

@berimbolo: Нитка, що чекає, врешті-решт прокинеться сповіщенням. Планувальник вирішить, про яку потоку очікування надходить повідомлення.
Натан Х'юз

підраховує щось, ви говорите, спін-блокування, Блокована доза не означає, що це спін-блокування
Франк Чжан

16

Спрощена перспектива для інтерпретації відвалів потоків:

  • ЗАЧЕКАЙ - чекаю, що мені дадуть якусь роботу, тому я зараз простою.
  • Блокований - я зайнятий спробами закінчити роботу, але інша нитка стоїть на моєму шляху, тому я простою зараз.
  • RUNNABLE ... (Native Method) - Я закликав RUN деякий нативний код (який ще не закінчений), що стосується JVM, ви RUNNABLE і він не може дати більше інформації. Поширеним прикладом може бути метод рідного слухача сокетів, закодований в C, який насправді чекає прибуття будь-якого трафіку, тому я зараз простою. У цій ситуації це може розглядатися як особливий вид ЗАЧЕКАЙТЕ, оскільки ми насправді НЕ РАБОЧИМ (немає запису процесора) взагалі, але вам доведеться використовувати дамп потоку ОС, а не дамп потоку Java, щоб побачити це.

1
Мені подобається ваше пояснення. Це саме те, що я зараз намагаюся зробити, аналізуючи скидання ниток :)
Шрідхар Сарнобат

@MuhammadGelbana Так, ви праві, я видалив коментар.
Ерік Ван

1
Ваш RUNNABLEне зовсім прав. Це може бути в черзі запуску Java, але не виконуватись, або воно може виконувати код Java. Це не повинно викликати рідну землю.
Сірий

1

Заблоковано - Ваш потік перебуває у стані експлуатації потоку життєвого циклу потоку та намагається отримати блокування об'єкта. Зачекайте - Ваш потік знаходиться в стані очікування життєвого циклу потоку і чекає, коли сигнал сповіщення прийде в стан, який можна виконати.


-1

дивіться цей приклад:

демонстрація станів потоку.

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

Дякую за код, але я вважаю за краще мати текстову відповідь, а потім показати невеликий блок коду.
Сірий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.