0

我有四个线程使用 CompletableFuture 异步运行,如下面的代码所示。他们都应该访问“grownSeedXYList”。有时当我运行代码时,我没有收到任何错误,但有时我收到“java.util.concurrent.completionexception”,我认为这是因为“grownSeedXYList”不同步。

请让我知道如何同步“grownSeedXYList”?

更新

this.grownSeedXYList is a list that will be populated with some Point objects based on the runnable class used (GrowSeedSERun, GrowSeedNWRun, GrowSeedNERun, GrowSeedSWRun)

四个线程使用 Compltable future 运行

this.grownSeedXYList = new ArrayList<Point>();
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
                this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
                this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
                this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
                CompletableFuture.allOf(this.growSeedFutureList).join();

GrowSeedSERun 类

private class GrowSeedSERun implements Runnable {

    private Mat saliencyMat = null;
    private double seedVal;
    private Point seedXY = null;

    public GrowSeedSERun(Mat saliencyMat, Point seedXY, double seedVal) {
        // TODO Auto-generated constructor stub
        this.saliencyMat = saliencyMat;
        this.seedXY = seedXY;
        this.seedVal = seedVal;
    }
    public void run() {
        // TODO Auto-generated method stub
        growSeedsSE(this.saliencyMat, this.seedXY, this.seedVal);
    }
}

成长种子SE

private void growSeedsSE(Mat saliencyMat, Point seedXY, Double seedVal) {
    // TODO Auto-generated method stub
    int origX = (int) seedXY.x;
    int origY = (int) seedXY.y;

    if ( this.withinRange(saliencyMat.get(origY, ++origX)[0]) ) {

        if ( (this.grownSeedXYList != null) && (!this.grownSeedXYList.contains(new Point(origX, origY))) ) {

            //Log.D(TAG, "growSeedsSE", "newX: origX: "+origX);
            //Log.D(TAG, "growSeedsSE", "newX: origY: "+origY);
            //Log.D(TAG, "growSeedsSE", "newX: value: "+saliencyMat.get(origY, origX)[0]);

            this.grownSeedXYList.add(new Point(origX, origY));

        } else {
            Log.D(TAG, "growSeedsSE", "point: "+ new Point(origX, origY)+" contained in the list");
        }
        this.growSeedsSE(this.saliencyMat, new Point(origX, origY), this.saliencyMat.get(origY, origX)[0]);

    } else if ( this.withinRange(saliencyMat.get(++origY, (int) this.seedXY.x)[0]) ) {
        origX = (int) this.seedXY.x;

        if ( (this.grownSeedXYList != null) && (!this.grownSeedXYList.contains(new Point(origX, origY))) ) {

            //Log.D(TAG, "growSeedsSE", "newY: origX: "+origX);
            //Log.D(TAG, "growSeedsSE", "newY: origY: "+origY);
            //Log.D(TAG, "growSeedsSE", "newY: value: "+saliencyMat.get(origY, origX)[0]);

            this.grownSeedXYList.add(new Point(origX, origY));

        }  else {
            Log.D(TAG, "growSeedsSE", "point: "+ new Point(origX, origY)+" contained in the list");
        }
        this.growSeedsSE(this.saliencyMat, new Point(origX, origY), this.saliencyMat.get(origY, origX)[0]);
    }
}
4

2 回答 2

2

grownSeedXYList在线程之间共享。您最简单的选择是使用如下声明:

this.grownSeedXYList = Collections.synchronizedList(new ArrayList<Point>());

这将导致grownSeedXYList集合是线程安全的。仅供参考,我相信,在没有完整的回退的情况下CompletionException,您可能在调用时收到了它,join因为线程中的一个捕获了ConcurrentModificationException

编辑:正如@user270349 在下面的评论中所指出的那样,正如javadocgrownSeedXYList所指出的那样,如果你迭代它,你仍然需要同步。在这种情况下,您将执行以下操作:

synchronized(grownSeedXYList) {
    Iterator i = grownSeedXYList.iterator();
    while (i.hasNext())
        foo(i.next());
    }
}

但是,如果您使用 for/each 块,则不需要同步,如下所示:

for (Point point : grownSeedXYList) {
    foo(point);
}
于 2015-06-08T15:34:17.913 回答
1

在 Java 中,在资源周围使用互斥锁。

可以在这里找到带有转向标志的更安全的锁。 https://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class main {

    public static void main(String[] args) 
    {
        final Lock lock = new ReentrantLock();

        try {
            lock.tryLock();
        } finally {
            lock.unlock();
        }
    }
}
于 2015-06-08T15:25:32.047 回答