1

我正在使用java.util.concurrent.ExecutorService对所有可用处理资源执行并发计算。在下面的代码中,MyProcessor类的实例在其performParallelProcessing方法中创建了多个ProcessingExecutor类实例,并将它们提交给ExecutorService实例,以期获得相应的回调。为什么Java并发处理不适用于新实例化的对象,而它适用于同一类的反序列化对象?

处理发生在ProcessingExecutor类的performProcessing方法中。我用于处理的数据是类ComputationData的对象实例。它们可以从文件系统中检索(如果序列化数据存在),或者可以初始化为新实例。

这里的问题是:

在这种情况下,如果ComputationData对象实例从文件系统反序列化,并行处理执行,因为我希望它做的事。它在所有处理核心上并行运行,占用了100%的处理资源。

ComputationData对象实例被新初始化的情况下,并发处理不按照我的预期执行。它的运行就像是单线程执行,占用了大约15%的处理资源。

正如我所猜,我的新初始化的ComputationData对象实例有问题。但是我不知道他们有什么问题,以及为什么并发不适用于他们,而他们的序列化 - >反序列化版本。任何提示或想法将不胜感激。

public class MyProcessor { 
    private boolean processingFinished = false; 

    public void performParallelProcessing(){ 
     int count = 0; 
     boolean continueProcessing = true; 

     int nrOfProcessors = Runtime.getRuntime().availableProcessors(); 
     ExecutorService es = Executors.newFixedThreadPool(nrOfProcessors); 

     while (continueProcessing){ 
      ProcessingExecutor task = new ProcessingExecutor(count); 
      task.setCaller(this); 
      es.submit(task); 
      count++; 

      if (!processingFinished){ 
       try{ 
        Thread.sleep(50); 
       } 
       catch(SecurityException | InterruptedException e){ 
        //Exception handling 
       } 
      } 
      else{ 
       continueProcessing = false; 
      } 
     } 
    } 

    public void callBack(ProcessingResult result) { 
     if(result.allDataProcessed()){ 
      this.processingFinished = true; 
     } 
    } 
} 

public class ProcessingExecutor implements Callable { 
    private MyProcessor processor; 
    private int count; 

    public ProcessingExecutor(int count){ 
     this.count = count; 
    } 

    public Object call() { 
     ProcessingResult result = null; 
     try { 
      result = performProcessing(); 
     } 
     catch (SecurityException e) { 
      //Exception handling 
     } 

     processor.callBack(result);  
     return null; 
    } 

    public void setCaller(MyProcessor processor) { 
     this.processor = processor; 
    } 

    public MyProcessor getCaller() { 
     return this.processor; 
    } 

    private ProcessingResult performProcessing(){ 
     ComputationData data = null; 

     if(serializedDataExist()){ 
      data = getSerializedData(count); 
     } 
     else{ 
      data = initializeNewData(count); 
     } 

     ProcessingResult result = new ProcessingResult(data, count); 
     return result; 
    } 

    private ComputationData getSerializedData(int count){ 
     ComputationData data = null; 
     // code to retrieve a ComputationData object from the file system 
     // based on 'count' value. 
     return data; 
    } 

    private ComputationData initializeNewData(int count){ 
     ComputationData data = null; 
     // code to initialize a new instance of ComputationData class 
     // based on 'count' value. 
     return data; 
    } 

    private boolean serializedDataExist(){ 
     boolean dataFound = false; 
     // code to verify whether serialized ComputationData objects are 
     // present on the file system. 
     return dataFound; 
    } 
} 
+3

如果您认为问题出在ComputationData类上,那么将它包含在问题中是一个好主意。 – biziclop

+1

你有没有使用探查器来追踪发生了什么?我的猜测是反序列化是一直需要的,所以当你不这样做时,它会更快地完成,并且需要更少的cpu –

+1

序列化是CPU密集型过程,而分配新对象并不是相对的。你怎么知道第一个人正在利用100%的资源?你只是看着你的任务管理器? – Arkantos

回答

1

为什么你需要Thread.sleep(50)?这是使并发执行成为顺序执行的一种方式,特别是如果每​​次计算都是< = 50毫秒。我的猜测是反序列化时间+计算时间超过50毫秒,这就是为什么在反序列化对象场景中,您有更多的CPU活动,因为您在执行程序线程中同时有效地执行多个任务。你应该尝试没有Thread.sleep(50)或至少有一个小得多的超时。

+0

Bravo et merci! 'Thread.sleep(50)'的确是原因。你的解释是正确的。但是,如果我彻底清除睡眠,那么由于某种原因,执行永远不会结束。引入一个非常短的睡眠时间(例如'Thread.sleep(1)')允许执行按预期完成。现在我还不明白原因,为什么睡眠是必要的。 – croset3

+0

一个可能的问题是,您正在从主线程读取'processingFinished'并从一个或多个执行程序线程设置其值。你应该同步所有访问这个变量,例如'synchronized(this){processingFinished = true; }'。使用同步的getter和setter可能更容易。 – Lolo

+0

这也是一个有用的说明,正确地解释原因!事实上,在没有睡眠的情况下未完成执行的原因是没有同步。我的实际代码比我提交的样本更复杂。 'Thread.sleep()'实际上确保了从标准输入流中读取输入数据的同步。但是,你是对的,如果我使用'synchronized' getters和setter,它会更有效率。非常感谢您的有用评论! – croset3

相关问题