BewareMyPower commented on PR #23217:
URL: https://github.com/apache/pulsar/pull/23217#issuecomment-2309610378
> Some map implementations don't have an atomic computeIfAbsent
implementation
A more accurate description is that the `ConcurrentSkipListMap` does not
guarantee if `mappingFunction` argument is called the computed value must be
inserted to the map.
Given the following example:
Thread 1:
```java
final var result1 = map.computeIfAbsent("key", __ -> {
System.out.println("value1");
return "value1";
});
```
Thread 2:
```java
final var result2 = map.computeIfAbsent("key", __ -> {
System.out.println("value2");
return "value2";
});
```
There is a case that both "value1" and "value2" are printed but `result1`
and `result2` are the same ("value1" or "value2").
However, it's expected because the Java Language Specification only
guarantees the happens-before relationship on concurrent collections, see
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html#Weakly
> The methods of all classes in java.util.concurrent and its subpackages
extend these guarantees to higher-level synchronization. In particular:
> - Actions in a thread prior to placing an object into any concurrent
collection happen-before actions subsequent to the access or removal of that
element from the collection in another thread.
Let's simplify and extend the example above.
Thread 1:
```java
final var result1 = map.computeIfAbsent("key", __ -> "value1"); // A
final var result3 = map.get("key"); // C
```
Thread 2:
```java
final var result2 = map.computeIfAbsent("key", __ -> "value2"); // B
final var result4 = map.get("key"); // D
```
There are only two possible cases for the `ConcurrentSkipListMap` (and
`ConcurrentHashMap`): `value1` and `value2`. If it's `value1`, then we will
have A happens-before B because the behavior is just like:
1. A inserted "key -> value1" and succeeded
2. A returned "value1" because it's inserted
3. B inserted "key -> value2" and failed
4. B returned the existing value "value1"
The "concurrent" hash map only guarantees B could not return a value other
than "value1". Because the last write operation before the read operation of B
is A so B could only see "value1" written by A.
Besides, the concurrent map only guarantees:
- `result3` is "value1" because A happens-before C, A reads "value1" and
there is no other write operation between A and C
- `result4` is "value1" before B happens-before D, B reads "value1" and
there is no other write operation between B and D
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]