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?
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!).
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 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.
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.
Related
I do not have a background in CS. I am really new to parallel programming and I do not know how exactly the hardware works when running a program. However, I have noticed the following. Say I have:
public class Counter {
private static int parallelCount = 0;
private static int sequentialCount = 0;
public static void main(String[] args) {
int n = 1000;
// I count in parallel:
IntStream.range(0, n).parallel().forEach(i -> {
parallelCount++;
});
// I count sequentially:
for (int i = 0; i < n; i++) {
sequentialCount++;
}
System.out.println("parallelCount = " + parallelCount);
System.out.println("sequentialCount = " + sequentialCount);
}
}
why I may get:
parallelCount = 984
sequentialCount = 1000
I guess this has to do with the hardware and the way the compiler access memory. I am really interested to know why this happens. And what is one possible solution?
Whenever more than one threads can access a value that is mutable then the system goes out of sync meaning the kind of problem that you are facing. No one can be sure what the result will be, and many a times the result will be wrong. You cannot guarantee which thread will write the value last.
Therefore, you need to synchronize the access to the shared resource (the integer you are incrementing) so that all threads get the latest updated value and the answer is always correct.
Coming to your program you can try making the parallelCount variable an Atomic Integer like AtomicInteger parallelCount = new AtomicInteger(); An Atomic Integer is thread safe meaning that they can be concurrently updated without running the system out of sync.
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class Counter {
private static AtomicInteger parallelCount = new AtomicInteger();
private static int sequentialCount = 0;
public static void main(String[] args) {
int n = 1000;
// I count in parallel:
IntStream.range(0, n).parallel().forEach(i -> {
parallelCount.getAndIncrement();
});
// I count sequentially:
for (int i = 0; i < n; i++) {
sequentialCount++;
}
System.out.println("parallelCount = " + parallelCount);
System.out.println("sequentialCount = " + sequentialCount);
}
}
As you can expect standard for loop will increment sequentialCount 1000 times
Regarding parallel stream, the application will try to open multiple threads which need to execute your function on parallel. In this situation, multiple threads can increment value at the same time and store value to int.
For example, suppose that we have two threads that working parallel and want to increment value from variable parallelCount. If parallelCount contains value 50. Both threads will read value 50 and calculate the new value 51 and store it to memory.
This approach can produce other concurrent problems. In order to solve this problem, you can use synchronization, locking, atomic classes, or another approach.
Multiple theads do an operation that is not atomic (incrementing a value).
The code you wrote translates to byte code and might cause something like this:
To avoid this, you need to synchronize the access to that critical code.
But note, that if all of your code is critical code, then it's redundant to use multiple threads.
AtomicInteger
We can make use of AtomicInteger class from Java concurrency package while working with parallel streams as the behavior can be unpredictable while using primitive data type
import java.util.stream.IntStream;
import java.util.concurrent.atomic.AtomicInteger;
public class Main
{
private static AtomicInteger parallelCount = new AtomicInteger();
private static int sequentialCount = 0;
public static void main(String[] args) {
System.out.println("Hello World");
int n = 100000;
// I count in parallel:
IntStream.range(0, n).parallel().forEach(i -> {
parallelCount.incrementAndGet();
});
// I count sequentially:
for (int i = 0; i < n; i++) {
sequentialCount++;
}
System.out.println("parallelCount = " + parallelCount);
System.out.println("sequentialCount = " + sequentialCount);
}
}
I had a question when I learned the HashMap source code in java8。
Source code is so complicated, how much efficiency?
So I wrote a code about the hash conflict。
public class Test {
final int i;
public Test(int i) {
this.i = i;
}
public static void main(String[] args) {
java.util.HashMap<Test, Test> set = new java.util.HashMap<Test, Test>();
long time;
Test last;
Random random = new Random(0);
int i = 0;
for (int max = 1; max < 200000; max <<= 1) {
long c1 = 0, c2 = 0;
int t = 0;
for (; i < max; i++, t++) {
last = new Test(random.nextInt());
time = System.nanoTime();
set.put(last, last);
c1 += (System.nanoTime() - time);
last = new Test(random.nextInt());
time = System.nanoTime();
set.get(last);
c2 += (System.nanoTime() - time);
}
System.out.format("%d\t%d\t%d\n", max, (c1 / t), (c2 / t));
}
}
public int hashCode() {
return 0;
}
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Test))
return false;
Test t = (Test) obj;
return t.i == this.i;
}
}
I show the results in Excel。
enter image description here
I am using java6u45 java7u80 java8u131。
I do not understand why the performance of java8 will be so bad
I'm trying to write my own HashMap.
I would like to learn HashMap in java8 which is better, but I did not find it.
Your test scenario is non-optimal for Java 8 HashMap. HashMap in Java 8 optimizes collisions by using binary trees for any hash chains longer than a given threshold. However, this only works if the key type is comparable. If it isn't then the overhead of testing to see if the optimization is possible actually makes Java 8 HashMap slower. (The slow-down is more than I expected ... but that's another topic.)
Change your Test class to implement Comparable<Test> ... and you should see that Java 8 performs better than the others when the proportion of hash collisions is large enough.
Note that the tree optimization should be considered as a defensive measure for the case where the hash function doesn't perform. The optimization turns O(N) worst-case performance to O(logN) worst-case.
If you want your HashMap instances to have O(1) lookup, you should make sure that you use a good hash function for the key type. If the probability of collision is minimized, the optimization is moot.
Source code is so complicated, how much efficiency?
It is explained in the comments in the source code. And probably other places that Google can find for you :-)
Is there any scenario in which AtomicInteger.accumulateAndGet() can't be replaced with AtomicInteger.updateAndGet(), or is it just a convenience for method references?
Here's a simple example where I don't see any functional difference:
AtomicInteger i = new AtomicInteger();
i.accumulateAndGet(5, Math::max);
i.updateAndGet(x -> Math.max(x, 5));
Obviously, the same goes for getAndUpdate() and getAndAccumulate().
When in doubt, you may look into implementation:
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
They differ only in single line and obviously accumulateAndGet could be expressed easily via updateAndGet:
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
return updateAndGet(prev -> accumulatorFunction.applyAsInt(prev, x));
}
So updateAndGet is somewhat more basic operation and accumulateAndGet is a useful shortcut. Such shortcut might be especially helpful if your x is not effectively final:
int nextValue = 5;
if(something) nextValue = 6;
i.accumulateAndGet(nextValue, Math::max);
// i.updateAndGet(prev -> Math.max(prev, nextValue)); -- will not work
There are cases where an instance creation can be avoided by using accumulateAndGet.
This is not really a functional difference but it might be useful to know about.
Consider the following example:
void increment(int incValue, AtomicInteger i) {
// The lambda is closed over incValue. Because of this the created
// IntUnaryOperator will have a field which contains incValue.
// Because of this a new instance must be allocated on every call
// to the increment method.
i.updateAndGet(value -> incValue + value);
// The lambda is not closed over anything. The same
// IntBinaryOperator instance can be used on every call to the
// increment method.
//
// It can be cached in a field, or maybe the optimizer is able
// to reuse it automatically.
IntBinaryOperator accumulatorFunction =
(incValueParam, value) -> incValueParam + value;
i.accumulateAndGet(incValue, accumulatorFunction);
}
Instance creations are generally not expensive but can be important to get rid of in short operations that are used very frequently in performance sensitive locations.
More information about when lambda instances are reused can be found in this answer.
I've been given the task to find the way to share a method's, involved in several threads, local variable, so it's value would be visible for every thread running this method.
Now my code look's like this:
public class SumBarrier2 implements Barrier {
int thread_num; // number of threads to handle
int thread_accessed; // number of threads come up the barrier
volatile int last_sum; // sum to be returned after new lifecyrcle
volatile int sum; // working variable to sum up the values
public SumBarrier2(int thread_num){
this.thread_num = thread_num;
thread_accessed = 0;
last_sum = 0;
sum = 0;
}
public synchronized void addValue(int value){
sum += value;
}
public synchronized void nullValues(){
thread_accessed = 0;
sum = 0;
}
#Override
public synchronized int waitBarrier(int value){
int shared_local_sum;
thread_accessed++;
addValue(value);
if(thread_accessed < thread_num){
// If this is not the last thread
try{
this.wait();
} catch(InterruptedException e){
System.out.println("Exception caught");
}
} else if(thread_num == thread_accessed){
last_sum = sum;
nullValues();
this.notifyAll();
} else if (thread_accessed > thread_num ) {
System.out.println("Something got wrong!");
}
return last_sum;
}
}
So the task is to replace the class member
volatile int last_sum
with method's waitBarrier local variable, so it's value would be visible to all threads.
Any suggestions?
Is it even possible?
Thanks in advance.
In case the variable last_sum is updated by only one thread, then declaring it volatile will work. If not then you should look at AtomicInteger
An int value that may be updated atomically. See the
java.util.concurrent.atomic package specification for description of
the properties of atomic variables. An AtomicInteger is used in
applications such as atomically incremented counters, and cannot be
used as a replacement for an Integer. However, this class does extend
Number to allow uniform access by tools and utilities that deal with
numerically-based classes.
You can have the practical uses of AtomicInteger here: Practical uses for AtomicInteger
I need to generate monotonically increasing integers.
Could I use the timestamp to somehow generate such type of integer sequence?
I would request an integer at a time, and I won't be requesting more than an integer in the same second's interval - if I do, I won't mind if it passes me the same integer within that second's interval.
You can use an AtomicInteger object to maintain a thread safe counter. Then use getAndIncrement() when you need the next integer.
Since monotonically increasing integers do not need to be contiguous (ie there can be gaps, as long as the number keeps increasing), and it sounds like you want all calls made in the same second to return the same integer, a method that returns how many seconds the JVM has been up would do nicely.
Here's a simple implementation that does that:
private static long startTime = System.currentTimeMillis();
public static int secondsSinceStart() {
return (int) TimeUnit.SECONDS.convert(
System.currentTimeMillis() - startTime, TimeUnit.MILLISECONDS);
}
FYI, this would last 68 years before rolling over.
This is my self made generator...
public final class IdGenerator {
private static final int MAGNITUDE = 10000;
private static long previousTimestamp;
private static int counter = 0;
private IdGenerator() {
}
public synchronized static long generateId() {
final long timeMillis = System.currentTimeMillis();
if (previousTimestamp != timeMillis) {
counter = 0;
}
previousTimestamp = timeMillis;
final int counterValue = counter++;
if (counterValue >= MAGNITUDE) {
//just to be sure
throw new IllegalStateException("too many id generated for a single timestamp!");
}
return timeMillis * MAGNITUDE + counterValue;
}
}