方法检查锁,锁释放后运行

Method checks for lock, runs after lock released

我面临潜在的追逐错误。我使用 javafx TableView 来显示我的数据,并且我定期从外部接收更新请求,该请求调用我的更新函数。我也有一些听众做一些事情,比如处理 mousedrag 事件等。我想做的是做这样的事情:

private void handleEvent(){
  TableView.setRowFactory(new Callback<TableView<MyModel>, TableRow<MyModel>>(){
    public TableRow<MyModel> call(TableView<MyModel> p) {
      final TableRow row = new TableRow();
      row.setOnDragDetected(new EventHandler<MouseEvent>(){
        public void handle(){
          //implement some kind of lock to prevent receiving data update
        }
      }
      row.setOnMouseDragExited(new EventHandler<MouseDragEvent>(){
        //release lock to accept update
      }
   }
}

//this method is being called externally periodically
public void updateModel(MyModel model){
  //this won't work because it will skip entirely if it's locked,
  //I want it to instead run later when lock is released
  if (!locked){
    this.model = model;
  }
}

我做了一个快速的解决方法,如 updateModel 方法所示,使用布尔值来锁定和解锁,问题是它会丢失一些更新的数据,因为它被完全跳过了。相反,我希望它 运行 稍后释放锁时.. 我如何实现这种锁机制和 运行 以后的功能?

编辑:为什么我怀疑这是因为我的听众正在操纵和获取 table 数据..虽然数据不断更新,但我不确定这是否导致我的 table休息。

只需编写一些逻辑,收集您在锁定状态下尝试执行的所有操作,并在解锁时执行。

以下代码假定您正在使用 Platform.runLater 或在应用程序线程上进行更新 运行 的类似代码。

public class UpdateSynchronizer {

    private final List<Runnable> pendingUpdates = new ArrayList<>();
    private boolean locked = false;

    public void lock() {
        if (locked) {
            throw new IllegalStateException("double lock");
        } else {
            locked = true;
        }
    }

    public void runUpdate(Runnable updater) {
        if (updater == null) {
            throw new IllegalArgumentException();
        }

        if (locked) {
            pendingUpdates.add(updater);
        } else {
            updater.run();
        }
    }

    public void unlock() {
        for (Runnable r : pendingUpdates) {
            try {
                r.run();
            } catch(Exception ex) {
                ex.printStackTrace(); // print but ignore
            }
        }
        pendingUpdates.clear();
        locked = false;
    }

}

如果上次更新总是覆盖之前更新的所有数据,那么只保留一个 Runnable 而不是一个列表会更高效。

private final UpdateSynchronizer synchronizer = new UpdateSynchronizer();

// why did all the keywords start with uppercase letters (compile time error)
private void handleEvent(){
  TableView.setRowFactory(new Callback<TableView<myModel>, TableRow<myModel>>(){
    public TableRow<myModel> call(TableView<myModel> p) {
      final TableRow row = new TableRow();
      row.setOnDragDetected(new EventHandler<MouseEvent>(){
        public void handle(){
           synchronizer.lock();
           //implement some kind of lock to prevent receiving data update
        }
      }
      row.setOnMouseDragExited(new EventHandler<MouseDragEvent>(){
        //release lock to accept update
        synchronizer.unlock();
      }
   }
}

//this method is being called externally periodically
public void updateModel(myModel model){
  synchronizer.runUpdate(() -> {
      // this is just an assignment and won't have any side effects
      // updates to the scene may only happen, if the model is accessed in some event handler or animation
      this.model = model;

  });
}