Java: NotifyObserver и DeadLock в потоке - PullRequest
1 голос
/ 26 марта 2012

У меня проблема с Observer-Pattern и тупиком с использованием потоков.

package observerDeadLock;

import java.util.Observable;

public class MyModel extends Observable {
Integer foo;

public MyModel() {
    foo = 0;
}

public void changeStatus(Integer newStatus) {
    foo = newStatus;
    notifyObservers(newStatus);     
}
}

package observerDeadLock;

public class Job extends Thread {
    public MyModel model;

    public Job(MyModel model) {
        super();

        this.model = model;
    }

    public void run() {
        prepareJob();
        runMyJob();
    }

    private void runMyJob() {
        // Some stuff
        Integer choice = 1;

        if (choice == 3) {
            return;
        }
        else if (choice == 2) {
            return;
        }
        else if (choice == 1) {                                     
            model.changeStatus(123);    // Set a particalar status that MyController receive as wrong!
                    // PROBLEM: The Controller listen the changeStatus(123) of notifyObserver of MyModel and call a join() because I want the thread join and quit()
            return; // <<- NEVER EXECUTED! join(timeout) isn't the solution IHMO...s
        }       

        return;
    }

    private void prepareJob() {
        // Do some stuff
    }

}

package observerDeadLock;

import java.util.Observable;
import java.util.Observer;

public class MyController implements Observer {
    private Job myJob;
    private MyModel model;

    public MyController() {

    }

    public void startJob() {
        model = new MyModel();
        model.addObserver(this);

        myJob = new Job(model);
        myJob.start();
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof MyModel) {
            if (((Integer) arg) == 1) {     
                // do other stuff
            }
            else if (((Integer) arg) == 2) {        
                // do other stuff
            }
            else if (((Integer) arg) == 123) {      // 123 => Wrong state for myController, so must stop Job
                // Stop myJob!!!
                try {
                    //myJob.join(timeout); // isn' the solution IHMO

                    myJob.join();               // PROBLEM HERE!!! In job, the "return" statment is locked in changeStatus() -> myModel.notifyobserver() that lock here in JOIN();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }           
            }


        }
    }
}

Что я могу сделать, чтобы решить эту проблему?Я полагаю, что использование Thread.join (), а не Thread.interrupt () - плохая практика ... Предложение?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 26 марта 2012

Вы явно пытаетесь join() текущий поток (вы можете убедиться в этом сами, если замените myJob.join() на System.out.println( Thread.currentThread() )), что не очень хорошая идея, так как поток будет зависать навсегда или пока кто-то другой не прервет его извне.

Вместо join(), просто позвоните interrupt(), в этом нет ничего постыдного. (Хотя будет ли это иметь какой-либо эффект, зависит от того, что еще в runMyJob())

Обновление: я могу только предположить, что вы отредактировали части своего кода для краткости, но если MyController действительно ничего не делает, если встречает выходное значение 123, чем остановка потока обновления, тогда вся конструкция ненужным. Вы должны просто вернуться из метода runMyJob(), ничего не устанавливая, и поток будет корректно остановлен.

3 голосов
/ 26 марта 2012

Похоже, у вас здесь есть логические ошибки:

  1. В runMyJob() вы звоните model.changeStatus(123)
  2. Это вызывает notifyObservers() в Observable
  3. Это уведомляет наблюдателей, вызывая MyController.update()
  4. Затем попытается join() в потоке.

Поскольку поток является тем, который вызывает update(), он пытается соединиться с самим собой, что, очевидно, не будет работать. Я бы хотел, чтобы основной поток просто сделал соединение после начала:

myJob.start();
myJob.join();

Вы также можете установить какое-то значение во время обновления (возможно, volatile int или AtomicInteger), которое затем может быть прочитано основным потоком.

Если вы отредактируете свой вопрос, чтобы сообщить нам, чего вы пытаетесь достичь, я исправлю свой ответ, чтобы предоставить некоторые более точные рекомендации.

...