Race condition occurring during use of Parallel Streams and Atomic Variables

不羁岁月 提交于 2021-02-18 18:01:14

问题


When the following piece of code is getting executed I am getting exceptions in a random manner.

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 function:

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();
}

As can be seen from above the code is making use of parallel streams and then calling getResult Function. Also there is an atomic variable involved. When the atomicVariable is true the store function is called and when it is false the fetch function is called.

My understanding is that inside getResult function we are checking and updating atomic variable aBoolean and this check and update operation is atomic but new Store(...).call(); and new Fetch(...).call(); is not and since parallel streams involves multiple threads so there is a race-condition occurring at

return aBoolean.getAndSet(!aBoolean.get()) ?
                          new Store(new ByteArrayInputStream(loremIpsumContentArray[i / 2]), repository, path).call() :
                          new Fetch(repository, path).call();

In order to corroborate my theory of Race condition I added the lock as shown below to both new Store(...).call() and new Fetch(...).call() as shown below and then everything worked fine:

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());

And getResult function:

return aBoolean.getAndSet(!aBoolean.get()) ?
                          new Store(new ByteArrayInputStream(loremIpsumContentArray[i / 2]), repository, path, lock).call() :
                          new Fetch(repository, path, lock).call();

I have the following questions:

  • Is my understanding correct regarding the race condition occurring as mentioned above and have I used the lock in the way they should be?

  • What are the other ways to avoid the race condition?

Please, let me know your thoughts.


回答1:


Your aBoolean.getAndSet(!aBoolean.get()) is not atomic. Some thread can hop between !aBoolean.get() and the surrounding aBoolean.getAndSet which might lead to the race condition.

You should synchronize the block:

boolean whatToExec;
synchronized (aBoolean) {
    whatToExec = aBoolean.get();
    aBoolean.set(!whatToExec);
}
return whatToExec ? ...

What the lock is good for in Fetch or Store is unknown. If the race condition happens there, I currently have no answer.



来源:https://stackoverflow.com/questions/55843518/race-condition-occurring-during-use-of-parallel-streams-and-atomic-variables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!