如何编写多个代码并累积单个文件中所有线程的输出

时间:2013-10-04 19:11:10

标签: java multithreading concurrency

这个问题与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);   
    }
}

问题/疑问

我尝试的多线程代码似乎运行正常,因为我可以在控制台中看到预期的输出,但我不能再使用myLongRunningMethodfileWriter的输出写入文件了。另外,我可以在分析器中看到即使在完成处理后所有线程仍处于活动状态myObject

如何在处理myObjectSet中的所有元素后在文件中写入输出。即以多线程方式恢复原始功能。然后停止所有线程。

有没有更容易/更好的实施?也许涉及番石榴的Futures 我真的需要使用类似于Semaphore

中的代码的MyResource

顺便说一句,我尝试将outString设置为MyClassMT的字段,并尝试在threadExec.execute(myClassMT);之后的代码中将其恢复,但这不起作用。

代码中未显示,将为每个myObjectSet创建一个新的fileWriter。

如果需要更多相关信息,请与我们联系。

2 个答案:

答案 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)

我想说这只是多线程中标准(多个)生产者 - 消费者问题的另一种变体。针对这类问题有很多不同的解决方案,在这种情况下我更倾向于消息队列方法 - 但这只是我个人的偏好。