【问题标题】:How to call a method in a multi-threaded way that returns elements of a List如何以多线程方式调用返回列表元素的方法
【发布时间】:2016-06-06 04:49:10
【问题描述】:

我有这个方法:

    public List<String> composeList (DataBaseObject dBO) {
    List<String> valueList = new ArrayList<>();
       for (String separatedFieldName : separatedFieldNames) {
           object = PropertyUtils.getProperty(object, separatedFieldName);
           valueList.add(object.toString());
       }                        
    }

我有一个包含 1000 个dBO 对象的列表,并希望以多线程方式调用此方法。

但是这个方法的返回也会进入一个列表

这里是调用者:

List<List<String>> valueLists =  new ArrayList<>();
    for (DataBaseObject dBO : listOfDBOs)
    valueLists.add(composeList(dBOObject));

由于现在的机器有多个内核,我想知道如何使用它们。就像我如何在并行中调用 composeList 并将结果存储在一个 ArrayList 中一样。

我知道我可以使用 Collections.SynchronizedList,但是 composeList 的执行时间非常短,以至于我最终会按顺序添加元素,即使是多线程的,它仍然是顺序执行,因为每次添加都会放锁定 Sysnchronized 列表。

这听起来像是一个设计问题,但它仍然与编程相关。对于这种情况,我非常感谢任何帮助。

【问题讨论】:

  • 我认为您不能同时安全地写入对象。您可以在运行另一个任务时调用列表填充器,但不能让两个任务同时编辑同一个列表。这就是为什么 SynchronizedLists 在这样使用时基本上是顺序行为,这是唯一安全的方法。
  • 就像我说的,这不一定是与列表人口有关的问题。也许你也可以提出一些关于设计的建议。不幸的是,我必须等待列表人口完成才能完成下一个任务。所以不能同时调用其他任何东西。
  • 在你的例子中不清楚,为什么添加到valueList 是在循环之外。据我了解,您要添加所有字段的所有值?
  • @KenBekov 哦抱歉打错了

标签: java multithreading arraylist


【解决方案1】:

可能,这个解决方案有点“传统风格”,没有任何酷炫的新东西,比如 stream 等,但我会做如下的事情:

public class AnyClass {

    private static final AtomicInteger index = new AtomicInteger(0);
    private static final Object lock = new Object();      

    public class ComposerThread implements Runnable {

        private List<DataBaseObject> dboList;
        private List<List<String>> valueList;
        private List<String> fieldNames;

        public MyThread(List<DataBaseObject> dboList, List<List<String>> valueList, 
                        List<String> fieldNames) {
            this.valueList= valueList;
            this.dboList = dboList;
            this.fieldNames = fieldNames;
        }

        public void run() {
            int i = index.getAndIncrement(); //thread takes next unprocessed index
            while(i<dboList.size()){
                DataBaseObject object = dboList.get(i);
                List<String> list = new ArrayList<>();
                for (String separatedFieldName : fieldNames) {
                    Object object = PropertyUtils.getProperty(object, separatedFieldName);
                    list.add(object.toString());
                }  

                synchronized (lock) {  //addition synchronized
                    valueList.add(list);
                }
                i = index.getAndIncrement(); //thread takes next unprocessed index
            }
        }
    }
    ....
}

注意,AtomicInteger index 和 Object lock 必须是 final static,因为在同步中使用。现在您可以在同一个父类中使用ComposerThread 内部类:

public class AnyClass{

    ....

    private List<List<String>> composeValueList(List<DataBaseObject> dboList,
                                                List<String> fieldNames, int threadCount) {

        index.set(0);//reset index before process dboList
        List<List<String>> valueList = new List<List<String>>();

        Thread [] pool = new Thread[threadCount];
        for(int i=0; i<pool.length; i++){
            pool[i] = new Thread(new ComposerThread (objectList, valueList, fieldNames));
            pool[i].start();
        }
        for(Thread thread : threadPool){
            thread.join(); //just wait while all will be done
        }
        return valueList;
    }
}

如您所见,您甚至可以设置线程数。

【讨论】:

    【解决方案2】:

    Java 8 并行流正是为这种情况而设计的。

    List<String> dbFieldValues = dbObjectList.parallelStream()
        .flatMap(seperatedFieldNames().parallelStream()
            .map(fn -> PropertyUtils.getProperty(db, fn).toString()))
        .collect(Collectors.toList());
    

    假设seperatedFieldNames 的集合支持并行流(例如ArrayList),这将使用多个线程,而无需自己创建它们。

    请注意,这是假设 getProperty 没有副作用。

    【讨论】:

    • 你的答案是肯定的,但不幸的是,至少现在我无法迁移应用程序以使用 Java8
    【解决方案3】:

    阅读 Java 中的 ExecutorService 和 ForkJoin 框架。它可以帮助你实现你想要的。

    谢谢。

    【讨论】:

      猜你喜欢
      • 2015-07-20
      • 1970-01-01
      • 1970-01-01
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-04
      • 1970-01-01
      相关资源
      最近更新 更多