Question

I was surprised that Java's AtomicInteger and AtomicLong classes don't have methods for modular increments (so that the value wraps around to zero after hitting a limit).

I figure I've got to be missing something obvious. What's the best way to do this?

For example, I want to share a simple int between threads, and I want each thread to be able to increment it, say, mod 10.

I can create a class which uses synchronization/locks, but is there a better, easier way?

Was it helpful?

Solution

What's difficult about adding a synchronized modifier or block to your addModular() method?

The reason why the Atomic classes don't have this functionality is that they're based on specific atomic hardware instructions offered by current CPUs, and modular arithmetic cannot be implemented by those without resorting to locking or other more complex and potentially inefficient algorithms like the one suggested by matt.

OTHER TIPS

Just mod 10 the value when you read from it?

public class AtomicWrappingCounter {
  private final AtomicLong counter = new AtomicLong();
  private final int max;

  public AtomicWrappingCounter(int max) {
    this.max = max;
  }

  public int get() {
    return (int) (counter.get() % max);
  }

  public int incrementAndGet() {
    return (int) (counter.incrementAndGet() % max);
  }
}

Obviously if you might increment this counter more than Long.MAX_VALUE times, you couldn't use this approach, but 9 quintillion is a lot of times to be incrementing (around 292 years at a rate of 1 per nanosecond!).

I would think the simplest way is to build a wrapping counter yourself which stores it's values in an AtomicInteger, something like

public class AtomicWrappingCounter {
    private AtomicInteger value;
    private final int max;

    public AtomicWrappingCounter(int start, int max) {
        this.value = new AtomicInteger(start);
        this.max = max;
    }

    public int get() {
        return value.get();
    }

    /* Simple modification of AtomicInteger.incrementAndGet() */
    public int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = (current + 1) % max;
            if (value.compareAndSet(current, next))
                return next;
        }
    }
}

Why doesn't AtomicInteger provide something like this itself? Who knows, but I think the intention of the concurrency framework authors were to provide some building blocks you could use to better create your own higher-level functions.

In Java 8 you can use getAndUpdate (and updateAndGet) in AtomicInteger.

For example if we want to have a counter that wraps to zero each time it hits 10.

AtomicInteger counter = new AtomicInteger(0);

// to get & update
counter.getAndUpdate(value -> (value + 1) % 10)

I was surprised that Java's AtomicInteger and AtomicLong classes don't have methods for modular increments.

Don't be surprised when a standard class does not include "bells and whistles" to support all sorts of unusual use-cases. The designers have to draw a line somewhere on what they include and what they don't include. The tendency is to support common use cases and use cases that cannot possibly be supported any other way. In this case, neither of these criteria apply.

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