以下是我想要做的事情的简介,我有一个场景
我计划在最短的时间内完成任务,因此尝试编写并行执行程序来执行对这些文件的检查。
我的想法是
我的理解是这样我应该能够在最短的时间内完成每日检查。
我的代码如下,让我感到困惑“如何在每个线程完成后将所有线程的结果存储在单个集合中”,我的直觉是我正在做一些有趣(不正确)的方式我正在存储结果。
第二个问题想检查是否有人在下面的代码段中讨论任何其他问题
第三个问题这似乎是一个常见的用例(对我来说)任何设计模式代码片段的指针解决这个问题
注意:我使用的是JDK 6.
public class CheckExecutor {
// to store all results of all threads here , then this will be converted to html/pdf files
static ConcurrentLinkedQueue<Result> fileWiseResult = new ConcurrentLinkedQueue<Result>();
public static void main(String[] args) {
int numberOfThreads=n; // need keep it configurable
Collection<ABCCheck> checksToExecute // will populate from business logic , ABCCheck is interface , has a method check() , there are different implementations
ConcurrentLinkedQueue<File> fileQueue = new ConcurrentLinkedQueue<File>(); // list of files for 1 day , may vary from 0 to 8
int maxNumOfFiles = fileQueue.size();
ThreadGroup tg = new ThreadGroup ("Group");
// If more number of threads than files (rare , can be considered corener case)
if (maxNumOfFiles < numberOfThreads) numberOfThreads=maxNumOfFiles;
// loop and start number of threads
for(int var=0;var<numberOfThreads;var++)
{
File currentFile = fileQueue.remove();
// execute all checks on 1 file using checksToExecute
ExecuteAllChecks checksToRun = new ExecuteAllChecks(); // business logic to populate checks
checksToRun.setchecksToExecute(checksToExecute);
checksToRun.setcheckResult(fileWiseResult); // when each check finishes want to store result here
new Thread (tg , checksToRun , "Threads for "+currentFile.getName()).start();
}
// To complete the tasak ... asap ... want to start a new thread as soon as any of current thread ends (diff files diff sizes)
while(!fileQueue.isEmpty()) {
try {
Thread.sleep(10000); // Not sure If this will cause main thread to sleep (i think it will pause current thread ) i want to pause main thread
} catch (InterruptedException e) {
e.printStackTrace();
}
// check processing of how many files completed
if( (tg.activeCount()<numberOfThreads) && (fileQueue.size()>0) ) {
int numOfThreadsToStart = numberOfThreads - tg.activeCount();
for(int var1=0;var1<numOfThreadsToStart;var1++) {
File currentFile = fileQueue.remove();
ExecuteAllchecks checksToRun = new ExecuteAllchecks();
checksToRun.setchecksToExecute(checksToExecute);
checksToRun.setcheckResult(fileWiseResult); // when each check finishes want to store result here
new Thread (tg , checksToRun , "Threads for "+currentFile.getName()).start();
}
}
}
}
}
class ExecuteAllchecks implements Runnable {
private Collection<ABCCheck> checksToExecute;
private ConcurrentLinkedQueue<Result> checkResult; // not sure if its correct , i want to store result off all threads here
public ConcurrentLinkedQueue<Result> getcheckResult() {
return checkResult;
}
// plan to instantiate the result collection globally and store result here
public void setcheckResult(ConcurrentLinkedQueue<Result> checkResult) {
this.checkResult = checkResult;
}
public Collection<ABCCheck> getchecksToExecute() {
return checksToExecute;
}
public void setchecksToExecute(Collection<ABCCheck> checksToExecute) {
this.checksToExecute = checksToExecute;
}
@Override
public void run() {
Result currentFileResult = new Result();
// TODO Auto-generated method stub
System.out.println("Execute All checks for 1 file");
// each check runs and calls setters on currentFileResult
checkResult.add(currentFileResult);
}
}
答案 0 :(得分:3)
实际的实现很大程度上受到计算本身的影响,但有些一般的方法可能是:
private final ExecutorService executor = Executors.newCachedThreadPool();
private final int taskCount = ...;
private void process() {
Collection< Callable< Result > > tasks = new ArrayList<>( taskCount );
for( int i = 0; i < taskCount; i++ ) {
tasks.add( new Callable< Result >() {
@Override
public Result call() throws Exception {
// TODO implement your logic and return result
...
return result;
}
} );
}
List< Future< Result > > futures = executor.invokeAll( tasks );
List< Result > results = new ArrayList<>( taskCount );
for( Future< Result > future : futures ) {
results.add( future.get() );
}
}
我还建议在future.get()
调用上使用合理的超时,以便执行线程不被卡住。
尽管如此,我还不建议在生产中使用缓存线程池,因为只要当前池没有足够的容量用于所有任务,此池就会增加,而是使用类似Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() )
我实际的任务可能是分成几个小的,后来加入考虑检查如何使用ForkJoin framework
有效地完成