【问题标题】:JavaFX. Adding items to the list in different threads is not workingJavaFX。将项目添加到不同线程中的列表不起作用
【发布时间】:2016-11-23 15:05:51
【问题描述】:

我有 2 节课。 第一类是控制器。当您点击enter按钮时,在集合中添加许多不同线程中的对象,并在循环10次迭代后退出时将此集合呈现为控制器的类。

public class Controller {
    private int count = 3;

    @FXML
    private Button enter;

    @FXML
    public void getData() throws IOException{
        //Create collection
        List<String> synchList = Collections.synchronizedList(new ArrayList<String>());

        ExecutorService executor = Executors.newFixedThreadPool(count);

        for (int i=0; i<10; i++) {

            Runnable myThread= new MyThread(synchList); 
            executor.execute(myThread);

        }

        executor.shutdown();

        System.out.println(synchList); //Show collection
}

第二类是MyThread。它执行一些任务。接收到的对象提前存储在collection中(例如,延迟添加3个对象,模拟一些任务的性能)

public class MyThread implements Runnable{
    public List<String> list = null; 

    public MyThread(List<String> list){
        this.list = list;   
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            list.add("Object2");
            Thread.sleep(2000);
            list.add("Object3");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在代码执行结束时,我得到一个空列表。请告诉我我做错了什么以及如何解决这种情况?谢谢!

【问题讨论】:

标签: java multithreading javafx collections


【解决方案1】:

看看the documentation of ExecutorService.shutdown:

启动有序关闭,其中执行先前提交的任务,但不会接受新任务。如果已经关闭,则调用没有额外的效果。

此方法不会等待之前提交的任务完成执行。

使用shutdown 只会阻止提交新任务。它并不能确保所有任务都已完成。

相反,您可以使用awaitTermination 来达到预期的效果:

executor.shutdown();

while (true) {
    try {
        if (executor.awaitTermination(1, TimeUnit.HOURS)) {
            break;
        }
    } catch (InterruptedException ex) {
    }
}

System.out.println(synchList); //Show collection

但是,您应该确保代码不是从应用程序线程运行的,否则 GUI 会变得无响应...

更新

如果您希望按顺序添加结果,使用 MyThread 实现 Callback&lt;List&lt;String&gt;&gt; 并使用结果将是更好的选择,因为这允许您从任务(最终列表的子列表)中检索结果和将结果合并到一个列表中:

public class MyThread implements Callable<List<String>> {

    @Override
    public List<String> call() throws Exception {
        List<String> list = new ArrayList(2);
        Thread.sleep(2000);
        list.add("Object2");
        Thread.sleep(2000);
        list.add("Object3");
        Thread.sleep(2000);
        return list;
    }
}
//Create collection
List<String> resultList = new ArrayList<>();

ExecutorService executor = Executors.newFixedThreadPool(count);

Callable<List<String>>[] tasks = new Callable[10];
for (int i = 0; i < tasks.length; i++) {
    tasks[i] = new MyThread();
}

List<Future<List<String>>> futures = executor.invokeAll(Arrays.asList(tasks));
executor.shutdown();

for (Future<List<String>> future : futures) {
    // combine results
    resultList.addAll(future.get());
}

System.out.println(resultList); //Show collection

【讨论】:

  • 哦,谢谢!这是工作!但是,如果我想按顺序添加集合中的对象,我可以使用什么?
  • @Tomas 在这种情况下,使用Future 确实更好(但也使用Callable&lt;List&lt;String&gt;&gt;),因为这正是Future 的用途。查看我的编辑。
  • 谢谢。这是很好的答案! @hoaz 在她的例子中也写过 Future
【解决方案2】:

在任务开始之前,您无需等待任务完成并关闭执行程序。 请尝试以下操作:

List<Future<?>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    Runnable myThread = new MyThread(synchList); 
    results.add(executor.submit(myThread));
}

// wait loop
for (Future<?> result : results) {
    result.get();
}

executor.shutdown();

【讨论】:

  • 谢谢!但是,您的意思是我需要向集合 List> results 添加另一个? p.s. results.add() 不起作用。
  • 是的,results.add 应该可以使用这种方法正常工作:Future&lt;?&gt; submit(Runnable task)
猜你喜欢
  • 1970-01-01
  • 2013-03-25
  • 1970-01-01
  • 2021-08-19
  • 2016-03-05
  • 1970-01-01
  • 2018-07-08
  • 2018-01-04
  • 2013-06-01
相关资源
最近更新 更多