当threadpool大于1时,结果不一致

时间:2018-03-22 17:12:02

标签: java multithreading

我几天来一直在努力解决这个问题,而不是本机java用户:

我有一个实现可调用的类来计算给定点的矢量/平面交点。 当我遍历网格时,我想调度一个线程来完成网格的每一行。

如果我设置Executors.newFixedThreadPool(1),它可以很好地工作。当我将其设置为2时,我得到不一致的结果, - 它部分跳过每一行的某些部分,返回的交集列表中的条目数少于预期。

我怀疑这是由于一些内存冲突,但我的理解是每个线程应该有自己的一组独立数据对象,因为我提交了新的doProjection()。 (有没有办法保证这个/强制同步访问,如果它们由ref传递?

提交/设置代码

ExecutorService service = Executors.newFixedThreadPool(2);
CompletionService<List<Integer>> ecs = new ExecutorCompletionService<List<Integer>>(service);
List<Future<List<Integer>>> contentsfutures = new ArrayList<>(subdiv[dim1]);
for (int dir1=0;dir1<subdiv[dim1] ;dir1++) {
    // make this so it selects the shortest side - adjust direction vector and projpoint[i]
    aprojpoint[dim1]=aprojpoint[dim1] + (adelta[dim1]*(dir1+1));      
    Future<List<Integer>> keepthis = ecs.submit(new doProjection(aprojpoint,adelta,aprojvector,asurfacetridef,dim1,dim2,subdiv[dim2],dx,dy,dz,meshsize,bounds,centroidmap,dir1));
    contentsfutures.add(keepthis);
}
List<Integer> temp = new ArrayList<>();
for (int dir1=0;dir1<subdiv[dim1] ;dir1++) {
    try {
        Future<List<Integer>> res1 = ecs.take();
        temp = res1.get();
    }
    catch (Exception ex) {
        ex.printStackTrace(System.out);
    }
    if (!temp.isEmpty()) {
        for (int i=0;i<temp.size()-2;i++) {
            // do stuff in my model
        }
    }
}

可调用类:

public class doProjection implements Callable<List<Integer>>{
     final private float[]projpoint;
     final private float[]initalpoint;
     final private float[]delta;
     final private float[] projvector;
     final private int dim1;
     final private int dim2;
     final private int ndim2; 
     final private int dir1;
     final private Map<Integer,tridef> surfacetridef; // big map
     final private float meshsize;
     final private float dx, dy, dz;
     final private gridbox bounds; // essentially float[][]
     //all of the items in the constructor ideally would be readonly
     final private Map<String,Integer> centroidmap; // big map

     public doProjection(float[] projpoint2, float[] delta2, float[] projvector2, 
                         Map<Integer,tridef> surfacetridef2,int dim11,int dim12, 
                         int dim12n,float dx2, float dy2, float dz2, float meshsize2, 
                         gridbox bounds2, Map<String,Integer> centroidmap2, int dir12) {
         this.dim1= dim11;
         this.dim2=dim12;
         this.projvector = projvector2;
         this.delta = new float[3];
         // etc other vars declared the same as the args
     }

     public List<Integer> call() throws Exception {
         List<Integer> keeplist = new ArrayList<>();
         int dir111 = dir1;
         for (int dir2=0;dir2<ndim2 ;dir2++) {           
             List<Float> intersectionlist=new ArrayList<>();
             // get list of distances to intersections with surface of interest.       
             intersectionlist = projectpointtoshells(surfacetridef,projpoint,projvector);
             // sorted list
             if (!intersectionlist.isEmpty()) {
                 List<Integer> subkeeplist = addelmstokeeplist( bounds, origin, endpoint,  dx, dy, dz, meshsize,centroidmap);
                 keeplist.addAll(subkeeplist);
             }
         }
     }

     keeplist.add(dir111); //some debug additions
     keeplist.add(ndim2);
     return keeplist;
}

谢谢!

可视化: - 缺少蓝色线内的间隙/虚假结果应该是实心的

enter image description here

1 个答案:

答案 0 :(得分:0)

Sean Bright提供了见解,

我没有意识到变化的变量projpoint是在线程之间共享的,因此被多个线程不一致地更新。

在doProjector构造函数中声明一个新的float [3]然后从projpoint分配值通过确保每个调用都有自己的投影点的本地副本来解决这个问题,所有其他变量都是readonly所以通常很高兴。