下面的代码执行时,我会以随机方式获取异常。
byte[][] loremIpsumContentArray = new byte[64][];
for (int i = 0; i < loremIpsumContentArray.length; i++)
{
random.nextBytes(loremIpsumContentArray[i] = new byte[CONTENT_SIZE]);
}
AtomicBoolean aBoolean = new AtomicBoolean(true);
List<Long> resultList = IntStream.range(0, 64* 2)
.parallel()
.mapToObj(i -> getResult(i,
aBoolean,
repositoryPath,
loremIpsumContentArray ))
.collect(Collectors.toList());
getResult
功能:
try
{
Repository repository = repositoryPath.getRepository();
String path = RepositoryFiles.relativizePath(repositoryPath);
//return aBoolean.compareAndSet(aBoolean.get(), !aBoolean.get()) ?
return aBoolean.getAndSet(!aBoolean.get()) ?
new Store(new ByteArrayInputStream(loremIpsumContentArray[i / 2]), repository, path, lock).call() :
new Fetch(repository, path, lock).call();
}
从上面可以看出,代码正在使用并行流,然后调用getResult
函数。此外,还涉及一个原子变量。当atomicVariable为true时,将调用store
函数;为false时,将调用fetch
函数。
我的理解是,在getResult函数内部,我们正在检查和更新原子变量aBoolean,并且此检查和更新操作是原子的,但是new Store(...).call();
和new Fetch(...).call();
不是原子的,并且由于并行流涉及多个线程,因此存在发生在
return aBoolean.getAndSet(!aBoolean.get()) ?
new Store(new ByteArrayInputStream(loremIpsumContentArray[i / 2]), repository, path).call() :
new Fetch(repository, path).call();
为了证实我的种族条件理论,我将如下所示的lock
分别添加到了new Store(...).call()
和new Fetch(...).call()
中,如下所示,然后一切正常很好:
Lock lock = new ReentrantLock();
AtomicBoolean aBoolean = new AtomicBoolean(true);
List<Long> resultList = IntStream.range(0, 64* 2)
.parallel()
.mapToObj(i -> getResult(i,
aBoolean,
repositoryPath,
loremIpsumContentArray,
lock))
.collect(Collectors.toList());
和getResult
函数:
return aBoolean.getAndSet(!aBoolean.get()) ?
new Store(new ByteArrayInputStream(loremIpsumContentArray[i / 2]), repository, path, lock).call() :
new Fetch(repository, path, lock).call();
我有以下问题:
对于上述发生的比赛情况,我的理解是否正确,我是否按应有的方式使用了锁?
还有其他避免比赛状况的方法吗?
请让我知道你的想法。
答案 0 :(得分:1)
您的aBoolean.getAndSet(!aBoolean.get())
不是原子的。
某些线程可能会在!aBoolean.get()
与周围的aBoolean.getAndSet
之间跳来跳去,这可能会导致竞争状态。
您应该同步块:
boolean whatToExec;
synchronized (aBoolean) {
whatToExec = aBoolean.get();
aBoolean.set(!whatToExec);
}
return whatToExec ? ...
在Fetch
或Store
中,锁定的作用是未知的。如果比赛条件在那里发生,我目前没有答案。