2016-01-26 4 views
0

У меня есть поток внутри класса, как this-Как уведомить всех наблюдателей, не удерживая нить?

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?

+0

'if (dat == 1)': Это сравнивает ссылки на объекты. Вместо этого вы хотите сравнить примитивный int. –

+0

@MarkusKull На самом деле он ничего не делает, кроме причины ошибки времени компиляции. Это то, что происходит, когда люди не публикуют фактический код, который они используют. – Kayaman

+0

@ Кайаман. У тебя все получилось. Извините, я не смог опубликовать свой полный код, потому что он слишком большой. Я написал эту демо-версию без компиляции. – Dipu

ответ

1

Вы звоните down.download(2) в пределах исполнения MyThread, поэтому поток все еще жив, что означает, что ваш метод загрузки ничего не делает из-за if(!myThread.isAlive()).

Я рекомендую вам использовать Executor framework и Listenable Futures from Guava вместо создания потоков вручную. Пример код из вики Гуавы:

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(..) Обратите внимание, что также имеет перегрузку, которая позволяет определить, какой исполнитель должен выполнить обратный вызов, это, кажется, что вы хотите.

+0

Я не знал об этой структуре. Думаю, я должен начать учиться. Благодарю. – Dipu

+2

Обратите также внимание на то, что Java 8 имеет [CompletableFuture] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html), что эквивалентно «ListenableFuture» от Guava. – Kayaman