我有四个线程使用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);
}
}
growSeedsSE :
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]);
}
}
答案 0 :(得分:2)
您的grownSeedXYList
在线程之间共享。您最简单的选择是使用声明如下:
this.grownSeedXYList = Collections.synchronizedList(new ArrayList<Point>());
这将导致grownSeedXYList
集合是线程安全的。我相信,因为在CompletionException
的调用中你可能收到了join
的{{1}}的完整回溯,因为在ConcurrentModificationException
修改:正如@ user270349在下面的评论中提到并javadoc所述,如果您对其进行迭代,则仍需要在grownSeedXYList
上进行同步。在这种情况下,您将执行以下操作:
synchronized(grownSeedXYList) {
Iterator i = grownSeedXYList.iterator();
while (i.hasNext())
foo(i.next());
}
}
但是,如果您使用for / each块,则不需要同步:
for (Point point : grownSeedXYList) {
foo(point);
}
答案 1 :(得分: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();
}
}
}