Спиране на възобновяване на нишки: Java

Когато стартирам този код, той показва следния изход:

One : 15 Two : 15 One : 14 Two : 14 Two : 13 One : 13 Two : 12 One : 12 One : 11 Two : 11 Thread 1 suspended Two : 10 Two : 9 Two : 8 Two : 7 Two : 6 Thread 1 resumed Thread 2 suspended Thread 2 resumed

Резултатът не продължава до края, който е Едно:1 Две:1 Не е ли изпълнен методът myresume на класа NewThread1? Каква е причината за това?

Следва кодът на NewThread1:

class NewThread1 implements Runnable{
String name;
Thread t;
boolean suspendFlag;

NewThread1(String threadname){
    name = threadname;
    t = new Thread(this, name);
    suspendFlag = false;
    t.start();
}

@Override
public void run(){
    try{ 
         for(int i=15; i>0; i--){
             System.out.println(name+ " : " +i);
             Thread.sleep(200);
                synchronized(this){
                    while(suspendFlag){
                        wait();
                    }
                }
        }
    }catch(InterruptedException e){
        System.out.println("New thread1 Interrupted");
    }
}
synchronized void myresume(){
    suspendFlag = false;
}
void mysuspend(){
    suspendFlag = true;
}
}        

Следва кодът на NewThread1: (методът main() е дефиниран тук)

public class Suspend_ResumeThreads {
public static void main(String args[]){
    NewThread1 ob1 = new NewThread1("One ");
    NewThread1 ob2 = new NewThread1("Two ");

    try{
        Thread.sleep(1000);
        ob1.mysuspend();
        System.out.println("Thread 1 suspended");
        Thread.sleep(1000);
        ob1.myresume();
        System.out.println("Thread 1 resumed");

        ob2.mysuspend();
        System.out.println("Thread 2 suspended");
        Thread.sleep(1000);
        ob2.myresume();
        System.out.println("Thread 2 resumed");

    }catch(InterruptedException e){
        System.out.println("Main Interrupted");
    }

    try{
        ob1.t.join();
        ob2.t.join();
    }catch(InterruptedException e){
        System.out.println("Main interrupeted in join()");
    }
System.out.println("Main exiting..");    
}
}

person Jainam Jhaveri    schedule 23.12.2014    source източник
comment
Трябва да извикате .notify() на същия обект, за да събудите нишка, заседнала в .wait() към този обект.   -  person Giulio Franco    schedule 23.12.2014
comment
Когато използвате notify/wait, това винаги трябва да се свързва с промяна на състоянието. Notify() може да възникне, когато нищо не чака и това ще бъде загубено, а wait() може да се събуди фалшиво.   -  person Peter Lawrey    schedule 23.12.2014
comment
Също така маркирайте suspendFlag като непостоянен. Или го променете в раздел synchronized   -  person talex    schedule 23.12.2014


Отговори (1)


Използвайте notifyAll, за да прекъснете wait(): пут

this.notifyAll();

във вашата функция myresume(). Но винаги бъдете готови това известие да се изгуби; по-специално, когато никоя нишка в момента не чака, тогава тя все още ще успее.

Уверете се, че сте synchronize/wait/notify на същия обект. Често срещана грешка е да се синхронизира на this и да не се осъзнае, че в контекста на анонимен вътрешен клас this може да е нещо различно. И още по-лошо, може да се промени при рефакторинг на кода! Най-добрата практика е да имате Object lock = new Object(); някъде и винаги synchronize(lock) ... lock.wait(); ... lock.notifyAll();, за да избегнете такива грешки при програмиране (и рефакторинг).

Освен ако не направите suspendFlag volatile, също има шанс различните нишки да видят различни стойности на това поле (ако не е volatile, нишките могат да запазят локално копие в кеша на процесора). По този начин може също да е добре да направите mysuspend също синхронизиран.

В някои случаи може да се наложи да преминете към по-разширена синхронизация, като например java.util.concurrent.locks.Lock и java.util.concurrent.Semaphore.

person Has QUIT--Anony-Mousse    schedule 23.12.2014