线程过早停止某些值

时间:2015-03-02 20:03:16

标签: java multithreading

背景

所以我正在编写一个应用程序,旨在执行蒙特卡罗模拟,以研究可以通过Moran过程(进化图论)进化的图形。对于无方向图,这可以很好地工作,但对于有向图,应用程序一直表现出奇怪的行为,我不能为我的生活找出原因。似乎发生的情况是,当此布尔变量isDirected设置为true时,线程会在满足循环条件之前退出它们运行的​​for循环,尽管isDirected为false时正常工作。

图表由邻接矩阵表示,因此图表定向时代码的唯一区别是邻接矩阵是非对称的,但我看不出任何会产生影响的原因。

代码

主要相关代码是控制器的这一部分:

 //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

与Investigator类一样,其重要部分如下所示:

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值,有时一些线程将比其他线程更远但是从运行中更改跑。

我完全被这里难过,非常感谢你的帮助,谢谢。

2 个答案:

答案 0 :(得分:0)

看起来你可能会使用threadPool.shutdown()过早地终止线程;

来自文件: 此方法不会等待先前提交的任务完成执行。使用awaitTermination来做到这一点。

代码在awaitTermination之前调用.shutdown ......

答案 1 :(得分:0)

当ExecutorService正在运行任务时,如果抛出未处理的异常,它们有时会过早地结束。

每次拨打.submit(Runnable).submit(Callable)时,都会收到一个Future对象,表示该任务的最终完成情况。 Future对象有一个.get()方法,它将在任务完成时返回任务结果。调用此方法将阻塞,直到该结果可用。此外,如果任务抛出了任务代码未处理的异常,则对.get()的调用将抛出ExecutionException,它将包装实际抛出的异常。

如果您的代码由于未处理的异常而提前退出,请在提交执行任务时(在提交了您希望的所有任务之后)获取的每个Future对象上调用.get()并捕获任何ExecutionExceptions恰好被抛出来弄清楚实际的潜在问题是什么。