0

这个问题有点类似于Make an existing code in Java parallel/multithread

我没有找到特定于我的问题的答案,所以我在下面发布。

我正在尝试使现有的应用程序多线程化以减少执行时间。

这是我的(为简洁起见)简化版现有应用程序代码

for(MyClass myObject : myObjectSet) {              
    String outputString=myLongRunningMethod(myObject);   
    fileWriter.append(outputString+"\n");
}

fileWriter.close();    

在这里,我试图使它成为多线程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 中的所有元素后,如何将输出写入文件。即以多线程方式取回我的原始功能。然后停止所有线程。

有没有更容易/更好的实现?也许涉及番石榴期货的那个 我真的需要使用类似于这里的代码的 MyResource Semaphore

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

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

如果需要更多信息,请告诉我。

4

2 回答 2

3

处理完 myObjectSet 中的所有元素后,如何将输出写入文件。即以多线程方式取回我的原始功能。

使用Future<String>是这样做的正确方法。你需要MyClassMT变成 aCallable<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()which 将在需要时分叉一个新线程。确实,如果您的线程是 CPU 密集型的,您应该在具有固定线程池的内核数周围选择一些数字,而不是为每个任务分配一个新线程。

于 2013-10-04T19:14:32.733 回答
0

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

于 2013-10-04T19:47:23.233 回答