如何以多线程方式调用方法返回List的元素

时间:2016-02-24 03:58:09

标签: java multithreading arraylist

我有这个方法:

    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));

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

我知道我可以使用Collections.SynchronizedList但是后来composeList的执行时间很少,我最终会在序列中添加元素,即使是多线程,它仍然是顺序执行,因为每个add都会放锁定Sysnchronized列表。

这可能听起来像是一个设计问题但仍然与编程相关。我真的很感激这种情况的任何帮助。

3 个答案:

答案 0 :(得分:1)

Java 8并行流是针对这种情况而设计的。

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

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

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

答案 1 :(得分:0)

可能,这个解决方案有点“传统风格”没有任何很酷的新东西,比如 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 indexObject 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 :(得分:-1)

阅读java中的ExecutorServiceForkJoin框架。它可以帮助您实现您想要的目标。

谢谢你。