2015-05-30 50 views
1

我有一個關於我的java GUI管理的問題。我正在更新,但是當我試圖從ExecutorService線程編輯一些JText或JProgressbar時,什麼也沒有。爲什麼java swing不允許ExecutorService線程發生更改

爲什麼它被破壞?這是我的ControllerManager的:

public class UpdateManager extends AppManager { 
    private final List<Controller> controllers; 
    @Getter private final ExecutorService worker; 
    @Getter private final UserInterface form; 
    private boolean isEnd; 

    public UpdateManager() { 
     this.controllers = new ArrayList<>(); 
     this.form = new Form(this); 
     this.worker = Executors.newCachedThreadPool(); 
    } 

    @Override 
    public void start(Controller... controllers) { 
     form.initialize(); 

     this.controllers.addAll(Arrays.asList(controllers)); 

     for(Controller controller: controllers) 
      controller.start(); 
    } 

    @Override 
    public void end(boolean dispose) { 
     if(isEnd) return; 

     for(Controller controller: controllers) 
      controller.end(); 

     if(dispose) form.dispose(); 
     isEnd = true; 
    } 
} 

這裏是當我試圖改變一些標籤的例子:如果你看到

/** 
* Created by romain on 17/05/2015. 
*/ 
public class ReleaseController implements Controller { 
    private final AppManager manager; 
    @Getter private final LinkedBlockingDeque<URL> files; 
    private Future<?> future; 
    private final SerializedObject<SerializedReleases> serializedReleases; 
    private final SerializedObject<Integer> serializedRelease, serializedTimestamp; 

    public ReleaseController(AppManager manager) { 
     this.manager = manager; 
     this.files = new LinkedBlockingDeque<>(); 
     this.serializedReleases = SerializedObjectImpl.create(FileUtils.path("releases", "releases.dat"), true, null); 
     this.serializedRelease = SerializedObjectImpl.create(FileUtils.path("swtour", "release.int"), false, 0); 
     this.serializedTimestamp = SerializedObjectImpl.create(FileUtils.path("swtour", "timestamp.int"), false, 0); 
    } 

    /** 
    * TODO: checking local files 
    */ 
    @Override 
    public void start() { 
     this.future = manager.getWorker().submit(new Runnable() { 
      @Override 
      public void run() { 
       int release = serializedRelease.get(); 
       int serverRelease = serializedReleases.get().lastRelease(AppUtils.OS); 
       int result = serverRelease - release; 

       if(result == 0 || result < 0) { 
        manager.getForm().alreadyUpdated(); //HERE 
        return; 
       } 

       for(int i=release+1;i<serverRelease;i++) { 
        try { 
         files.addLast(new URL(
           FileUtils.path(Main.SERVER, "releases", AppUtils.OS.toString(), i + ".zip"))); 
        } catch(Exception e) { 
         System.out.println(e.getMessage()); 
        } 
       } 

       serializedRelease.setObject(serverRelease).write(); 
       serializedTimestamp.setObject((int)System.currentTimeMillis()).write(); 
      } 
     }); 
    } 

    @Override 
    public void end() { 
     if(future != null && !future.isCancelled()) 
      future.cancel(true); 
    } 

} 

正確,它:

manager.getForm().alreadyUpdated(); 

修改我的圖形用戶界面:

public void alreadyUpdated() { 
     content.getFirstLine().setText(""); 
     content.getSecondLine().setText("Your client is already up-to-date!"); 
     content.getPlayButton().setEnabled(true); 
} 

但沒有什麼..我的gui沒有改變! 謝謝

+2

你確定'alreadyUpdated'甚至被稱爲? 'result'的價值是什麼?另請參閱https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html。雖然這可能與問題無關,但您不應該同時更新Swing GUI。更新應該包含在對'invokeLater'或'invokeAndWait'的調用中。 – Radiodef

+0

我確定已調用alreadyUpdated方法。謝謝你的回覆 –

回答

3

有兩個問題,試圖從另一個線程更新Swing的數據結構:

  1. Swing不是設計爲多線程安全的。你可能會破壞它的數據結構。
  2. 沒有什麼強制它看到在另一個線程中所做的更改。它可以使用寄存器或緩存中的值不受存儲器更改影響。

正如在評論中已經指出的那樣,您需要使用invokeAndWaitinvokeLater來更改Swing事件處理線程。

+0

好的謝謝你的男孩 –