Java.util.concurrent code overview

I study the java.util.concurrent library and find many infinite loops in the source code, like this

 //java.util.concurrent.atomic.AtomicInteger by Doug Lea public final int getAndSet(int newValue) { for (;;) { int current = get(); if (compareAndSet(current, newValue)) return current; } } 

I wonder in what cases the actual value cannot be equal to the expected value (in this case, compareAndSet returns false)?

+4
source share
4 answers

When a value changes in another thread, get () and compareAndSet () can see different values. This is what you need to worry about in parallel library.

+3
source

Many modern processors have a compareAndSet() card for atomic hardware operation. This means that it is thread safe without requiring synchronization (which is a relatively expensive operation in comparison). However, it only compareAndSet() itself atomic, therefore for getAndSet() (i.e. set the variable to the given value and return the value that it had at that time, without the possibility of setting it to another value between ) the code uses the trick: first it gets the value, then it tries to compareAndSet() with the value that it just received and the new value. If this fails, the variable was manipulated by another thread between them, and the code tried again.

This is faster than using synchronization if compareAndSet() rarely works, i.e. if too many threads are written to the variable at the same time. In the extreme case, when many threads write to a variable at all times, synchronization can be really faster, because although there is an overhead for synchronization, other threads trying to access the variable will wait and wake up when it's their turn. rather than repeating the operation again.

+10
source

This is not an endless loop; it is good practice when working with the TAS algorithm (test and set). What the loop does is (a) read from memory (should be volatile semantics) (b) calculate a new value (c) write a new value if the old value has not changed.

In the database area, this is called optimistic locking. It exploits the fact that most concurrent updates for shared memory are invalid, in which case it is the cheapest way to do this.

In fact, this is basically what Unexpected Lock will do in the case of an uncontrolled case. It will read the value of the lock, and if it is unlocked, it will execute the CAS of the thread identifier, and if this happens, the lock will be saved. If this fails, someone else got a lock. Locks, although dealing with failure, are much more complicated than just repeating the operation over and over. They will continue to read it for a while until the lock is quickly unlocked (spin lock), and then usually goes into sleep mode so that other flows reach their turn (exponential shutdown).

+3
source

Here is the actual use of the compareAndSet operation: imagine that you are developing an algorithm that computes something in multiple threads.

Each thread remembers the old value and on its basis performs a complex calculation.

Then he wants to set the new result ONLY if the old value has not yet been changed by another calculation flow. If the old value is not expected, the thread discards its own operation, accepts the new value, and restarts the calculation. To do this, it uses compareAndSet .

In addition, other continuations will only receive fresh values ​​to continue the calculation.

"endless" loops are used to implement a "wait wait", which can be much cheaper than putting a thread to sleep, especially when the thread conflict is low.

Hooray!

+1
source

Source: https://habr.com/ru/post/1338625/


All Articles