我有一个包含100,000个对象的列表。想要尽快阅读列表。
将它们分成多个小型列表,每个500个对象
List<List<String>> smallerLists = Lists.partition(bigList, 500);
ExecutorService executor = Executors.newFixedThreadPool(smallerLists.size());
for(int i = 0; i < smallerLists.size();i++) {
MyXMLConverter xmlList = new MyXMLConverter(smallerLists.get(i));
executor.execute(xmlList);
}
executor.shutdown();
while (!executor.isTerminated()) {}
MyXMLConverter.java 再次使用50个线程的Executors来处理这500个对象List。
public MyXMLConverter(List<String> data){
this.data = data;
}
@Override
public void run() {
try {
convertLine();
} catch (Exception ex) {}
}
public void convertLine(){
ExecutorService executor = Executors.newFixedThreadPool(50);
for(int i = 0; i < data.size();i++) {
MyConverter worker = new MyConverter(list.get(i));
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {}
}
从List中获取对象耗费了大量时间。有没有更好的方法来做到这一点?请建议。
答案 0 :(得分:2)
由于每个项目的处理时间可能会有所不同,因此最好让每个工作线程直接从主列表中将下一个项目拉入进程,以便最后保持所有线程忙碌。
从共享列表中提取多线程最好使用其中一个并发集合。在您的情况下,ConcurrentLinkedQueue
将成为主要候选人。
因此,将列表复制到ConcurrentLinkedQueue
(或直接构建&#34;列表&#34;作为队列),让线程调用poll()
直到它返回null
}。
如果构建100000个元素的列表也需要时间,您甚至可以通过允许工作线程在构建队列时开始工作来启动该过程。为此,您使用LinkedBlockingQueue
,工作人员会拨打take()
。
然后你会在队列中添加一个特殊元素来标记结束,当一个worker得到结束标记时,它会把它放回到下一个worker的队列中,然后退出。
答案 1 :(得分:1)
有两个主要问题
while (!executor.isTerminated()) {}
我建议使用这样的东西。
ExecutorService executor = Executors.newFixedThreadPool(COUNT_OF_YOUR_PROCESSOR_CORESS * 2);
List<Future<?>> futureList = new ArrayList<Future<?>>();
for(String currentString : bigList) {
MyConverter worker = new MyConverter(currentString);
Future<?> future = executor.submit(worker);
futureList.add(future);
}
Collections.reverse(futureList);
for (Future<?> future : futureList){
future.get();
}
executor.shutdown(); //No worries. All task already executed here
或者如果你是Java 8上瘾那么
bigList.parallelStream().forEach(s -> new MyConverter(s).run());