Practical uses for AtomicInteger
There are two main uses of AtomicInteger
:
As an atomic counter (
incrementAndGet()
, etc) that can be used by many threads concurrentlyAs a primitive that supports compare-and-swap instruction (
compareAndSet()
) to implement non-blocking algorithms.Here is an example of non-blocking random number generator from Brian Göetz's Java Concurrency In Practice:
public class AtomicPseudoRandom extends PseudoRandom {
private AtomicInteger seed;
AtomicPseudoRandom(int seed) {
this.seed = new AtomicInteger(seed);
}
public int nextInt(int n) {
while (true) {
int s = seed.get();
int nextSeed = calculateNext(s);
if (seed.compareAndSet(s, nextSeed)) {
int remainder = s % n;
return remainder > 0 ? remainder : remainder + n;
}
}
}
...
}As you can see, it basically works almost the same way as
incrementAndGet()
, but performs arbitrary calculation (calculateNext()
) instead of increment (and processes the result before return).
Practical Uses for DoubleAdder in Java
AtomicInteger, AtomicLong and all other Atomic variables will often share a single cache line for updates. That means each time a write occurs, all threads using the same Atomic object will have a cache-invalidation which will force whatever slowdown is required to synchronize.
In systems where you concurrent add a lot, and a system where you are not dependent on the values to be exactly accurate, then a DoubleAdder is best. Each thread has their own adder object it is incrementing (allowing each thread to not invalidate another thread). At the end you can ask the DoubleAdder for the sum of all thread's incrementing values.
The most common use case one can think of to use a DoubleAdder is metrics or statistics. Often you need good-enough tracking of metrics but don't often need exact precision.
At the very end, when all threads have stopped, if you were to ask the DoubleAdder for the sum of all threads, then you will get 100% accuracy.
Is use of AtomicInteger for indexing in Stream a legit way?
The documentation of the java.util.stream
package states that:
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement, as well as other thread-safety hazards.
[...]
The ordering of side-effects may be surprising. Even when a pipeline is constrained to produce a result that is consistent with the encounter order of the stream source (for example,
IntStream.range(0,5).parallel().map(x -> x*2).toArray()
must produce[0, 2, 4, 6, 8]
), no guarantees are made as to the order in which the mapper function is applied to individual elements, or in what thread any behavioral parameter is executed for a given element.
This means that the elements may be processed out of order, and thus the Stream
-solutions may produce wrong results.
This is (at least for me) a killer argument against the two Stream
-solutions.
By the process of elimination, we only have the "traditional solution" left. And honestly, I do not see anything wrong with this solution. If we wanted to get rid of the for
-loop, we could re-write this code using a foreach
-loop:
boolean toUpper = false; // 1st String is not capitalized
for (String word : splits) {
stringBuilder.append(toUpper ? word.toUpperCase() : word);
toUpper = !toUpper;
}
For a streamified and (as far as I know) correct solution, take a look at Octavian R.'s answer.
Your question wrt. the "limits of streams" is opinion-based.
The answer to the question (s) ends here. The rest is my opinion and should be regarded as such.
In Octavian R.'s solution, an artificial index-set is created through a IntStream
, which is then used to access the String[]
. For me, this has a higher cognitive complexity than a simple for
- or foreach
-loop and I do not see any benefit in using streams instead of loops in this situation.
Properties of AtomicInteger
You should have searched before asking this here. From this question,
There are two main uses of AtomicInteger:
- As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently
- As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms.
So the answer to your question is Yes
Is it good practice to use AtomicInteger as a substitute for mutable Integer?
I do not think this is a good idea: using AtomicInteger
in contexts that are not inherently concurrent is misleading to the reader.
Using an array is not a good idea, either, even though technically it works well. The problem is that the resultant code is not too descriptive, in the sense that the "mapping" of indexes to their meanings (i.e. 0
-> odd, 1
-> even) is not visible from the API itself.
You would be better off with a mutable class that holds two properties:
public class OddEven {
int odd, even;
public int getOdd() {return odd;}
public int getEven() {return even;}
public void incOdd() {odd++;}
public void incEven() {even++;}
}
This achieves a very good readability, without creating a false impression that something concurrent is going on behind the scene.
Using AtomicInteger safely to check first
You need to write a loop. Assuming that count
is your AtomicInteger
reference, you would write something like:
while(true)
{
final int oldCount = count.get();
if(oldCount >= VALUE)
break;
if(count.compareAndSet(oldCount, oldCount + 1))
break;
}
The above will loop until either: (1) your if(count < VALUE)
condition is not satisfied; or (2) count
is successfully incremented. The use of compareAndSet
to perform the incrementation lets us guarantee that the value of count
is still oldCount
(and therefore still less than VALUE
) when we set its new value.
Does AtomicInteger handle synchronization?
Could there be possibility that they load same value of
int i
?
Yes, there is, but it's handled for you.
The incrementAndGet
method uses an atomic "compare and set" operation that sets the incremented value but only if a new value was not already set. If the compare fails, incrementAndGet
fetches the new value and tries again.
The net effect is, it is safe to use incrementAndGet
from multiple threads.
AtomicInteger: keep non-negative
In Java 8, yes:
atomicInteger.updateAndGet(i -> i > 0 ? i - 1 : i);
Before Java 8, no.
Related Topics
How to Lock Compiled Java Classes to Prevent Decompilation
Why Stringbuilder When There Is String
Convert Timestamp in Milliseconds to String Formatted Time in Java
How to Query Xml Using Namespaces in Java with Xpath
Convenient Way to Parse Incoming Multipart/Form-Data Parameters in a Servlet
Encrypt Password in Configuration Files
What Is This Spring.Jpa.Open-In-View=True Property in Spring Boot
How to Create a Temporary Directory/Folder in Java
Fastest Way to Write Huge Data in Text File Java
Memory Address of Variables in Java
Java8 Lambdas VS Anonymous Classes
How to Fix the "Java.Security.Cert.Certificateexception: No Subject Alternative Names Present" Error
Java List.Add() Unsupportedoperationexception