我有这个方法:
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列表。
这可能听起来像是一个设计问题但仍然与编程相关。我真的很感激这种情况的任何帮助。
答案 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 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 :(得分:-1)
阅读java中的ExecutorService
和ForkJoin
框架。它可以帮助您实现您想要的目标。