如何在不持有线程的情况下通知所有观察者?

时间:2016-01-26 07:39:27

标签: java multithreading observers

我在像这样的类中有一个线程 -

import java.util.Observable;

public class Download extends Observable {

    private int state = 0;
    private final Thread myThread = new Thread(() -> {
        /*
         some work to do here
         */
        setChanged();
        notifyObservers(state);
    });

    public void download(int state) {
        if (!myThread.isAlive()) {
            this.state = state;
            myThread.start();
        }
    }

    public Thread getThread() {
        return myThread;
    }

    public static void MyMethod() throws InterruptedException {
        Download down = new Download();
        down.addObserver((Observable ob, Object dat) -> {
            System.out.println(ob);
            if ((int) dat == 1) {
                down.download(2);
            } else {
                System.out.println("success");
            }
        });
        down.download(1);
        down.getThread().join();
    }

    public static void main() throws InterruptedException {
        MyMethod();
    }
}

问题是我从来没有打印过"success"消息。

我认为,这是因为所有观察者都是从MyThread内部得到通知的。因此,当down.download(2)内的观察者调用MyMethod()时,前一个线程仍在运行,并且忽略该调用。

如何通过主线程而不是myThread通知所有观察者?

1 个答案:

答案 0 :(得分:1)

您正在执行down.download(2)内调用MyThread,因此线程仍处于活动状态,这意味着您的下载方法因if(!myThread.isAlive())而无效。

我建议您使用Executor frameworkListenable Futures from Guava,而不是手动创建线程。来自Guava wiki的示例代码:

ListeningExecutorService service = 
    MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
  public Explosion call() {
    return pushBigRedButton();
  }
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
  // we want this handler to run immediately after we push the big red button!
  public void onSuccess(Explosion explosion) {
    walkAwayFrom(explosion);
  }
  public void onFailure(Throwable thrown) {
    battleArchNemesis(); // escaped the explosion!
  }
});

注意Futures.addCallback(..)也有一个重载,允许你确定哪个执行者应该执行回调,这似乎是你想要的。