Practical Uses for Atomicinteger

Practical uses for AtomicInteger

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.

    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:

  1. As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently
  2. 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



Leave a reply



Submit