2015-03-02 60 views
1

背景線程過早地停止對某些值

所以我編寫的應用程序,旨在執行Monte Carlo模擬研究,可以通過莫蘭過程(進化圖論)進化圖。對於無向圖而言,這種方法非常完美,但對於有向圖而言,應用程序一直表現出奇怪的行爲,我不能爲了我的生活找出原因。看起來會發生的事情是,當這個布爾變量isDirected設置爲true時,儘管在isDirected爲false時正常工作,但線程在循環條件滿足之前退出它們運行的​​for循環。

這些圖由一個鄰接矩陣表示,所以當圖被引導時代碼中的唯一區別是鄰接矩陣是非對稱的,但是我看不到任何會產生影響的原因。

代碼

主要相關的代碼是從控制器本節:

//Initialise a threadPool and an array of investigators to provide each thread with an Investigator runnable 
      long startTime = System.nanoTime(); 
      int numThreads = 4; 
      Investigator[] invArray = new Investigator[numThreads]; 
      ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); 

      //Assign the tasks to the threads 
      for(int i=0;i<numThreads;i++){ 
       invArray[i] = new Investigator(vertLimit,iterations,graphNumber/numThreads,isDirected,mutantFitness,vertFloor); 
       threadPool.submit(invArray[i]); 
      } 
      threadPool.shutdown(); 

      //Wait till all the threads are finished, note this could cause the application to hang for the user if the threads deadlock 
      try{ 
       threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
      }catch(InterruptedException except){ 
       System.out.println("Thread interrupted"); 
      } 

      //The next two blocks average the results of the different threads into 1 array 
      double[] meanArray = new double[vertLimit]; 
      double[] meanError = new double[vertLimit]; 
      double[] fixProbArray = new double[vertLimit]; 
      double[] fixProbError = new double[vertLimit]; 

      for(int x=0;x<vertLimit;x++){ 
       for(Investigator i:invArray){ 
        meanArray[x] += i.getMeanArray()[x]; 
        meanError[x] += Math.pow(i.getMeanError()[x], 2); 
        fixProbArray[x] += i.getFixProbArray()[x]; 
        fixProbError[x] += Math.pow(i.getFixProbError()[x], 2); 
       } 
       meanArray[x] = meanArray[x]/numThreads; 
       fixProbArray[x] = fixProbArray[x]/numThreads; 

       meanError[x] = Math.sqrt(meanError[x]); 
       fixProbError[x] = Math.sqrt(fixProbError[x]); 
      } 

      long endTime = System.nanoTime(); 

      //The remaining code is for printing and producing graphs of the results 

除了研究者類,它的如下所示的重要部件:

public class Investigator implements Runnable{ 

public Investigator(int vertLimit,int iterations,int graphNumber,Boolean isDirected,int mutantFitness,int... vertFloor){ 
//Constructor just initialises all the class variables passed in 
} 

public void run(){ 
    GraphGenerator g = new GraphGenerator(); 
    Statistics stats = new Statistics(); 

    //The outer loop iterates through graphs with increasing number of vertices, this is the problematic loop that exits too early 
    for(int x = vertFloor>2?vertFloor:2; x < vertLimit; x++){     

     System.out.println("Current vertex amount: " + x); 
     double[] currentMean = new double[graphNumber]; 
     double[] currentMeanErr = new double[graphNumber]; 
     double[] currentFixProb = new double[graphNumber]; 
     double[] currentFixProbErr = new double[graphNumber]; 

     //This loop generates the required number of graphs of the given vertex number and performs a simulation on each one 
     for(int y=0;y<graphNumber;y++){ 

      Simulator s = new Simulator(); 
      matrix = g.randomGraph(x, isDirected, mutantFitness); 

      s.moranSimulation(iterations, matrix); 

      currentMean[y] = stats.freqMean(s.getFixationTimes()); 
      currentMeanErr[y] = stats.freqStandError(s.getFixationTimes()); 
      currentFixProb[y] = s.getFixationProb(); 
      currentFixProbErr[y] = stats.binomialStandardError(s.getFixationProb(), iterations); 
     } 

     meanArray[x] = Arrays.stream(currentMean).sum()/currentMean.length; 
     meanError[x] = Math.sqrt(Arrays.stream(currentMeanErr).map(i -> i*i).sum()); 

     fixProbArray[x] = Arrays.stream(currentFixProb).sum()/currentFixProb.length; 
     fixProbError[x] = Math.sqrt(Arrays.stream(currentFixProbErr).map(i -> i*i).sum());; 
    } 
} 

//A number of getter methods also provided here 
} 

問題

我已經放了一些打印語句,以瞭解發生了什麼事情,並且由於某種原因,當我將isDirected設置爲true時,線程在x到達vertLimit(我檢查過的確實是我指定的值)之前完成。我已經嘗試手動使用我的GraphGenerator.randomGraph()方法的有向圖,它給出了正確的輸出以及測試Simulator.moranSimulation(),這也適用於手動調用時的有向圖,並且我沒有得到線程中斷被我的catch塊捕獲,所以這也不是問題。

對於同一組參數,線程在不同的階段看起來是隨機的,有時它們在停止時都處於相同的x值,有時某些線程會比其他線程更進一步,跑步跑步。

我完全難住在這裏,真的很感謝一些幫助,謝謝。

+0

由於未處理的異常,您的線程可能會中止。試着抓住每次調用submit()返回的Future對象,一旦你有了所有未來的集合,就調用每一個的.get()方法。在即使你的線程拋出異常的情況下,.get()也會拋出一個ExecutionException,它包含了實際拋出的異常,然後你可以進行調查。 – djmorton 2015-03-02 20:25:13

+0

您也可以考慮使用ExecutorService的.invokeAll()方法,該方法將阻塞,直到所有任務完成,然後返回Future對象的集合。這可能比使用.shutdown()和awaitTermination()來確定你的任務完成的時候更習慣。 – djmorton 2015-03-02 20:28:05

+0

@djmorton非常感謝你,我之前沒有看到Future界面!事實證明,這是由統計類中的問題引起的零誤差除以有向圖。感謝所有的建議傢伙! – dl101 2015-03-02 21:16:13

回答

0

當任務正在由ExecutorService的運行,他們有時會出現提前結束,如果未處理的異常被拋出。

每當您撥打.submit(Runnable).submit(Callable)時,您都會收到一個Future對象,表示最終完成任務。 Future對象有一個.get()方法,它將在任務完成時返回任務結果。調用此方法將阻塞,直到該結果可用。另外,如果任務拋出一個異常,這個異常不會被你的任務代碼處理,那就調用。get()會拋出一個ExecutionException異常,它將包裹實際拋出的異常。

如果您的代碼由於未處理的異常而過早退出,請在您提交執行任務(在提交完所有任務後)並獲取任何ExecutionExceptions時獲取的每個Future對象上調用.get()碰巧發現真正的潛在問題是什麼。

0

它看起來像你可能會過早地用threadPool.shutdown()終止線程;

來自文檔: 此方法不會等待先前提交的任務完成執行。使用awaitTermination來做到這一點。

的代碼調用.shutdown awaitTermination前...