2014-10-02 40 views
0

JavaFX操作中的切换按钮将被2个独立的线程访问。是否在JavaFX原子中切换按钮的操作?

一个线程将尽快如果(a)成功 C)出口上的成功被调用为用户点击(切换按钮的状态),将 一)做一些在OS b)检查/退出并返回切换按钮之前的状态失败

另一个线程将监测异步到先前的操作(S)和在一个特定的事件它将改变按钮状态的情况下的事件。

我是否需要提供线程和锁定按钮状态方面之间的同步?

编辑:詹姆斯_D提出的想法似乎是合理的,但我只是想提出一种替代方案(其有效性仍有待证明)。 如何使用同步代码块,并且使用作为锁定参照特定的按钮,即是这样的:

// getting the reference to the button 
@FXML 
private ToggleButton tButtonToBeSynchronized 

// Thread1 
synchronized(tButtonToBeSynchronized) { 
// do stuff with button upon user click 
} 

// Thread2 
synchronized(tButtonToBeSynchronized) { 
// poll system every X seconds 
// when asynchronous event occurs (not related to UI events) 
// update tButtonToBeSynchronized state 
} 

会在情况下工作,这些是由不同的控制器类称为? (假设参考tButtonToBeSynchronized是通过引用传递的 - 而不是通过FXML框架的值传递的?

+0

不,这是行不通的。您也需要FX库代码来同步按钮。它不会 - 它假设您只访问FX应用程序线程中场景图的一部分的节点。即使它“有效”,但在Java 8中,如果尝试从另一个线程操纵状态,则会在运行时引发异常的显式检查。 – 2014-10-02 17:38:45

回答

2

与大多数UI工具包一样,JavaFX采用单线程模型,您应该只访问属于FX应用程序线程中的一个场景图,所以切换一个按钮并不是一个原子操作,你所描述的代码并不能保证它能够正常工作,在Java 8中,它可能会抛出一个RuntimeException.

JavaFX提供了启用与后台线程互操作的功能,其中最低级别为Platform.runLater(Runnable r),它在FX应用程序线程上执行r因此,您的显示器线程(您的问题中的第2项n)的应与

Platform.runLater(() -> toggleButton.setSelected(...)); 

还有一个javafx.concurrent API改变切换按钮的状态。这提供了一个Task类,其中包括Runnablejava.util.concurrent.FutureTask,另外还有一个回调方法的集合,用于在Task的生命周期中的各个点上提交要在FX应用程序线程上执行的代码。

所以,你应该在你的问题实施第1项为:

ExecutorService exec = ... ; // e.g. Executors.newCachedThreadPool(); 

toggleButton.selectedItemProperty().addListener((obs, wasSelected, isNowSelected) -> { 
    if (isNowSelected) { 
     Task<Void> task = new Task<Void>() { 
      @Override 
      public Void call() throws Exception { 
       // do something on OS 
       // throw exception if failed 
       return null ; 
      } 
     }; 
     task.setOnFailed(event -> toggleButton.setSelected(wasSelected)); 
     exec.submit(task); 
    } 
}); 

如果你喜欢返回指示成功或失败的值,你可以做

Task<Boolean> task = new Task<Boolean>() { 
    @Override 
    public Boolean call() { 
     // do work... 
     boolean successful = ... ; 
     return successful ; 
    } 
}; 
task.setOnSucceeded(event -> { 
    boolean wasSuccessful = task.getValue(); 
    // ... 
}); 
+0

感谢您花时间回复。我认为这会将事件处理/执行/调度的控制转移到内部JavaFX事件类型结构中?就像Qt框架一样? – pkaramol 2014-10-02 10:39:40

+0

我不知道Qt,但是; 'Platform.runLater(...)'在FX应用程序线程上执行提供的'Runnable'。 'Task'的'onSucceeded','onFailed'和类似的处理程序以及它的'updateXXX(...)'方法在同一个线程上执行。因此,在这些方法和处理程序中读取和写入属于场景图的一部分的节点的状态是安全的。 – 2014-10-02 11:12:08