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

相關問題