Question

I have a need for a counter of type long with the following requirements/facts:

  • Incrementing the counter should take as little time as possible.
  • The counter will only be written to by one thread.
  • Reading from the counter will be done in another thread.
  • The counter will be incremented regularly (as much as a few thousand times per second), but will only be read once every five seconds.
  • Precise accuracy isn't essential, only a rough idea of the size of the counter is good enough.
  • The counter is never cleared, decremented.

Based upon these requirements, how would you choose to implement your counter? As a simple long, as a volatile long or using an AtomicLong? Why?

At the moment I have a volatile long but was wondering whether another approach would be better. I am also incrementing my long by doing ++counter as opposed to counter++. Is this really any more efficient (as I have been led to believe elsewhere) because there is no assignment being done?

Was it helpful?

Solution

Given these sets of requirements, I think that a volatile long should be sufficient. The counter wouldn't be incorrect with a non-volatile long, but the reader might be reading stale information in that case.

One problem is that reads and writes to a long are not required to be atomic, by the JVM specification if it is not declared volatile. That would mean that the reading thread could get a pretty much fictive value if it reads the value while the writing thread has updated one part of the value, but not the other one.

The difference between ++counter and counter++ is probably irrelevant, as the JVM will realize that the value of the expression is not used any more and the two are equivalent in this case.

OTHER TIPS

In Java 8, use LongAdder which is even better than AtomicLong where thread contention is high.

LongAdder JavaDoc:

This class is usually preferable to AtomicLong when multiple threads update a common sum that is used for purposes such as collecting statistics, not for fine-grained synchronization control. Under low update contention, the two classes have similar characteristics. But under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.

what's the uptime requirement for your program? Could you make do with an un-volatile int and racy-reads?

10^4 increments / second is 1 every 100 usec. Efficiency is not an issue, but atomicity might be. You might have 2 copies of it, and when it is read, if they are not equal, read again.

This article talks about the possible ways to implement a counter I think this implementation should work for you

class LessNaiveVolatieIdGenerator {
private static volatile long id = 0;
public static long nextId() {
    long nextId = (id = id + 1); // or nextId = id++;
    return nextId;
}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top