从线程

时间:2017-05-09 00:21:22

标签: java javafx javafx-8

我正在设计Javafx中的多线程应用程序,并希望有一个TableView,其中包含每个Thread的Name和Progress的列。经过大量的研究后,我发现了一个类似的例子,说明了我在这里要完成的任务:

JavaFX Update progressbar in tableview from Task

(指出这一点:'https://community.oracle.com/message/10999916')

然而,我遇到的问题在这个例子中很好地说明了;如何多次调用'Task'对象来更新ProgressIndicator?

我从Oracle的文档中了解到,Task对象“是一次性的类,无法重用”。那么似乎只能调用Task对象的call()方法一次。我需要多次更新Task,因为它通过Thread类进行,而不是调用它一次,并通过For循环任意增加。

我已阅读有关绑定到Listeners和创建Service类的内容,但我不确定这些是否是对此问题的实际解决方案。因此,我想问一下,在Javafx中是否甚至可能这样,或者我是否忽略了某些东西。如果有人在过去完成了这项工作,那么如果您能够通过之前提供的示例说明如何,将会非常有用。

对此的任何指示都表示赞赏,谢谢。

-DREW

编辑1:我编辑了我的措辞,因为它不准确。

编辑2:这是一个带有一些伪代码的例子。假设我有一个包含以下代码的类:

public static class TaskEx extends Task<Void>{

  @Override
  protected Void call(){

    updateProgress(.5, 1);

  return null

}

public static void callThread() {
  TableView<TaskEx> table = new TableView<TaskEx>();
  //Some code for data in table.

  TableColumn progressColumn = new TableColumn ("Progress");
  progressColumn.setCellValueFactory(new PropertyValueFactor("progress");

  table.setItems(<data>);
  table.getColumns();addAll(progressColumn);

  ExecutorService executor = Executors.newFixedThreadPool(<SomeNumber>);

  for(TaskEx task : table.getItems(){
    Threading.ThreadClass newThread = new Threading.ThreadClass(task);
    executor.submit(newThread, <uniqueID>);
  }
}

然后说我用这个逻辑进行了第二堂课:

static class ThreadClass extends Thread{
  Task progressTask;

  public ThreadClass(Task task, Integer id){
    progressTask = task;
  }

public void run(){
  ExecutorService executor =  Executors.newFixedThreadPool(<someNumber>);

  //This invokes the Task call for the correct progressIndicator in the Tableview.
  //It will correctly set the progressIndicator to 50% done.
  executor.submit(progressTask);

  /* Main logic of the Threading class that involves the 'id' passed in. */

  //This will do nothing because you cannot invoke the Task call more than once.
  executor.submit(progressTask);
  }
}

这就是我需要的那种工作流程,但我不确定如何实现这一目标。

1 个答案:

答案 0 :(得分:1)

好像你没有得到我们所说的。您正在尝试在Thread.run()中执行逻辑,然后每个线程都创建一个Task,只是为了更新进度。

您需要的是将您的逻辑从Thread.run()转移到Task.call()。你的线程实际上只是一个线程,它只是运行一个Runnable对象(Task)。

public class TaskEx extends Task<Void> {
    @Override
    protected Void call() {
        // Do whatever you need this thread to do 
        updateProgress(0.5, 1);

        // Do the rest
        updateProgress(1, 1);
    }
}


public static void callThread() {
    TableView<TaskEx> table = new TableView<TaskEx>();
    ObservableList<TaskEx> data = FXCollections.observableArrayList<>();
    data.add(new TaskEx()); // Add the data you need

    TableColumn progressColumn = new TableColumn("Progress");
    progressColumn.setCellValueFactory(new PropertyValueFactory("progress"));
    progressColumn.setCellFactory(column -> {
        return new TableCell<TaskEx, Double> {
            private final ProgressBar bp = new ProgressBar();

            @Override
            public void updateItem(Double item, boolean empty) {
                super.updateItem(item, empty);

                if (empty || item == null) {
                    setText(null);
                    setGraphic(null);
                }
                else {
                    bp.setProgress(item.doubleValue());
                    setGraphic(bp);
                }
            }
        }
    });

    table.setItems(data);
    table.getColumns().add(progressColumn);

    ExecutorService executor = Executors.newFixedThreadPool(data.size());

    for (TaskEx task : table.getItems()) {
        executor.submit(task);
    }
}

此实现删除ThreadClass,因为不应该有任何必须在线程子类中完成的逻辑。如果您确实需要在逻辑中访问线程对象,请从Thread.getCurrentThread()致电TaskEx.call()

这个工具也会打开多个线程做同样的事情(这是毫无意义的)。如果您需要执行一组不同的逻辑,则可以创建一组不同的Task子类,或者添加一个构造函数来接收Runnable中的TaskEx个对象。

E.g。

public class TaskEx extends Task<Void> {
    private final Runnable[] logics;

    public TaskEx(Runnable[] logics) {
        this.logics = logics;
    }

    @Override
    protected Void call() {
        for (int i = 0; i < logics.length; i++) {
            logics[i].run();
            updateProgress(i, logics.length);
        }
    }
}