这个问题与Make an existing code in Java parallel/multithread
有些相似我没有找到特定于我的问题的答案,所以我在下面发帖。
我正在尝试使多线程的现有应用程序减少执行时间。
这是我的(为简洁起见)简化版现有的应用程序代码
for(MyClass myObject : myObjectSet) {
String outputString=myLongRunningMethod(myObject);
fileWriter.append(outputString+"\n");
}
fileWriter.close();
这里我试图让它成为多线程的.Becuase myLongRunningMethod
是最慢的。
ExecutorService threadExec = Executors.newFixedThreadPool(myObjectSet.size());
//信号量实现 ResourcePool resourcePool = new ResourcePool(myObjectSet.size());
for(MyClass myObject:myObjectSet) {
Object key = resourcePool.getItem();
MyClassMT myClassMT = new MyClassMT(myObject);
threadExec.execute(myClassMT);
}
MyClassMT在哪里:
public class MyClassMT implements Runnable{
MyClass myObject;
public MyClassMT(MyClass myObject) {
this.myObject=myObject
}
@Override
public void run() {
String outString= myLongRunningMethod(this.myObject);
System.out.println(outString);
}
}
问题/疑问
我尝试的多线程代码似乎运行正常,因为我可以在控制台中看到预期的输出,但我不能再使用myLongRunningMethod
将fileWriter
的输出写入文件了。另外,我可以在分析器中看到即使在完成处理后所有线程仍处于活动状态myObject
如何在处理myObjectSet中的所有元素后在文件中写入输出。即以多线程方式恢复原始功能。然后停止所有线程。
有没有更容易/更好的实施?也许涉及番石榴的Futures 我真的需要使用类似于Semaphore
中的代码的MyResource顺便说一句,我尝试将outString
设置为MyClassMT
的字段,并尝试在threadExec.execute(myClassMT);
之后的代码中将其恢复,但这不起作用。
代码中未显示,将为每个myObjectSet创建一个新的fileWriter。
如果需要更多相关信息,请与我们联系。
答案 0 :(得分:3)
如何在处理myObjectSet中的所有元素后在文件中写入输出。即以多线程方式恢复我的原始功能。
使用Future<String>
是正确的方法。您需要将MyClassMT
变为Callable<String>
并使用threadExec.submit(myCallable)
。这将返回Future<String>
,在您提交完所有任务后,可以使用它来获取每个线程的工作结果。
public class MyClassMT implements Callable<String> {
...
public String call() {
...
}
您还可以使用threadExec.invokeAll(...)
来调用所有Callable<String>
课程。这会返回List<Future<String>>
。
然后你可以做类似的事情:
List<Future<String>> futures = threadExec.invokeAll(myClassMTCollection);
// always shutdown the pool once you are done submitting
threadExec.shutdown();
for (Future<String> future : futures) {
// this can throw an exception that the thread threw
String result = future.get();
}
然后停止所有线程。
提交完所有任务后,您需要在池中调用shutdown()
。提交的作业继续运行,但一旦完成作业,线程将被关闭。如果你不这样做,你的申请将永远不会完成。
ExecutorService threadExec = Executors.newFixedThreadPool(myObjectSet.size());
如果你正在做这样的事情,那么你真的应该使用Executors.newCachedThreadPool()
,它会在需要时分叉一个新线程。实际上,如果你的线程是CPU密集型的,你应该在固定线程池的核心数量周围选择一些数字,并且不为每个任务分配一个新线程。
答案 1 :(得分:0)
我想说这只是多线程中标准(多个)生产者 - 消费者问题的另一种变体。针对这类问题有很多不同的解决方案,在这种情况下我更倾向于消息队列方法 - 但这只是我个人的偏好。