简体   繁体   中英

AtomicInteger or LongAccumulator

Can someone tell if LongAccumulator could be a better alternative for AtomicInteger in the below example?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class IncrementThread implements Runnable{

    AtomicInteger atomicint = new AtomicInteger();

    public IncrementThread(AtomicInteger atominint) {
        this.atomicint = atominint;

    }

    @Override
    public void run() {
        while(true)
            if(atomicint.incrementAndGet()==4){doSomething(); atomicint.set(0);}
    }

    private void doSomething() {
        System.out.println(Thread.currentThread().getName() + " : counter reached to 4");
    }

    public static void main(String[] args) {

        AtomicInteger atomicint = new AtomicInteger();
        IncrementThread incThread1 = new IncrementThread(atomicint);
        IncrementThread incThread2 = new IncrementThread(atomicint);
        IncrementThread incThread3 = new IncrementThread(atomicint);

        ExecutorService threadPool = Executors.newCachedThreadPool();

        threadPool.execute(incThread1);
        threadPool.execute(incThread2);
        threadPool.execute(incThread3);

    }

}

In this very exact example (which really does nothing useful) both classes seem to be equivalent.

With LongAccumulator you could pass the whole if statement as a lambda expression. But : The java doc of LongAccumulator states that the supplied function should be side effect free which is not fulfilled (doSomething writes to system out).

I suppose that you would probably use LongAccumulator in the same manner as AtomicInteger in this example. In that case the answer is no .

LongAccumulator accumulate values and count the result only, when you call methods like get(). You also make clearing similar LongAccumulator.reset() method, when it would be has 4 value. But all of this methods in LongAccumulator are not thread safe and you could get unpredictable results, because you use multiple threads for reading and updating.

LongAccumulator is good, when you know that many different threads will be update value, but the reading is seldom and more over, you should be sure that reading or reset happen only in one thread, if you matter about synchronization. But if you don't, LongAccumulator could be better. For example, when you want to count statistic, because if you want get statistic you more probably don't mean "statistic exactly in time of calling", you mean something like "current" results. This reasoning is applicable for LongAdder too.

In your example there are two possible improvements. First, you can use:

while(true)
        if(atomicint.incrementAndGet()==4){doSomething(); atomicint.compareAndSet(4, 0);}

Now you check, that you reset the same state of atomicint variable.

Another possible improvement - don't use AtomicLong or LongAccumulator, just use simple long variable with volatile keyword. It will be simpler and more applicable here, because in this example you don't use capabilities (like I mention in first improvement).

You could know more in documentation and classes' sources

  1. LongAdder
  2. LongAccumulator
  3. About volatile
  4. Most efficient - sources :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM