Doing a course on concurrent programming.
As an example we have
final class Counter {
private AtomicInteger value;
public long getValue() {
return value.get();
}
public long increment() {
int v;
do {
v = value.get();
}
while(!value.compareAndSet(v, v+1));
return v+1;
}
}
Why would you use compareAndSet in this case and not incrementAndGet ?
Thanks
Here the the implementation of AtomicInteger.incrementAndGet() method from the JDK version I have on my machine:
/**
* Atomically increments by one the current value.
*
* #return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
As you can see, the implementation is very similar to yours.
PS: Why do you compute v+1 twice?
From the Java docs,
compareAndSet :
Atomically sets the value to the given
updated value if the current value ==
the expected value.
public final boolean compareAndSet(V expect,
V update)
incrementAndGet :
Atomically increments by one the
current value.
public final int incrementAndGet()
Since compareAndSet basically does the same, I can't think about a single reason to use this handwritten implementation of increment.
In your case, the Class Counter implements the value increment in it's own way, and JDK AtomicInteger.incrementAndGet() also implements it in it's own way. But they also use the CAS method compareAndSet(V expect ,V newValue).
So these two kinds of implementation have no difference. The minor difference between the two ways is the circulation form. BTW, answer for compute v+1 twice.
while(!value.compareAndSet(v, v+1));----v+1 is the parameter for function , and realize value to add 1;
return v+1; v+1 is the return value;
Related
I have a class that is being called by multiple threads on multi core machine. I want to make it thread safe.
add method will be called by multiple threads. And if key exists, just append the current value to new value otherwise just put key and value in the map.
Now to make it thread safe, I was planning to synchronize add method but it will destroy performance. Is there any better way by which we can achieve better performance without synchronizing add method?
class Test {
private final Map<Integer, Integer> map = new ConcurrentHashMap<>();
public void add(int key, int value) {
if (map.containsKey(key)) {
int val = map.get(key);
map.put(key, val + value);
return;
}
map.put(key, value);
}
public Object getResult() {
return map.toString();
}
}
but it will destroy performance
It likely wouldn't destroy performance. It will reduce it some, with further reduction if there is a high collision rate.
Is there any better way by which we can achieve better performance?
Yes, use merge() (Java 8+). Quoting the javadoc:
If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null.
Example:
public void add(int key, int value) {
map.merge(key, value, (a, b) -> a + b);
}
Or using a method reference to sum(int a, int b) instead of a lambda expression:
public void add(int key, int value) {
map.merge(key, value, Integer::sum);
}
Use merge:
class Test {
final Map<Integer, Integer> map = new ConcurrentHashMap<>();
public void add(int key, int value) {
map.merge(key, value, Integer::sum);
}
public Object getResult() {
return map.toString();
}
}
Java 7 solution if you absolutely can't use synchronized (or, you absolutely cannot lock explicitly):
class Test {
final Map<Integer, AtomicInteger> map = new ConcurrentHashMap<>();
public void add(int key, int value) {
get(key).addAndGet(value);
}
private AtomicInteger get(int key) {
AtomicInteger current = map.get(key);
if (current == null) {
AtomicInteger ai = new AtomicInteger();
current = map.putIfAbsent(key, ai);
if (current == null) {
current = ai;
}
}
return current;
}
public Object getResult() {
return map.toString();
}
}
synchronized causes a bottleneck only when you run an expensive operation holding a lock.
In your case by adding a synchronized you are doing:
1. check a hashmap for existence of a key
2. get the value mapped to that key
3. do an addition and put the result back to the hashmap.
All these operations are super cheap O(1) and unless you are using some strange pattern for the keys which are integers it should be very unlikely that you can get some degenerate performance due to collisions.
I would suggest if you can't use merge as the other answers point out, to just synchronize. You should be considered so much about performance only in critical hotpaths and after you have actually profiled that there is an issue there
I have already asked this before how to generate auto increment ID Generate auto increment number by using Java.
I have used below code:
private static final AtomicInteger count = new AtomicInteger(0);
uniqueID = count.incrementAndGet();
The previous code working fine but the problem is count static variable. For this static its never start to 0 again, its always start with the last increment id. That is the issue.
Is there any alternative way except AtomicInteger?
Another issue is that I am working on GWT so AtomicInteger is not available in GWT.
So I have to find another way to do that.
AtomicInteger is a "signed" integer. It will increase till Integer.MAX_VALUE; then, due to integer overflow, you expect to get Integer.MIN_VALUE.
Unfortunately, most of the thread safe methods in AtomicInteger are final, including incrementAndGet(), so you cannot override them.
But you could create a custom class that wraps an AtomicInteger and you just create synchronized methods according to your needs. For instance:
public class PositiveAtomicInteger {
private AtomicInteger value;
//plz add additional checks if you always want to start from value>=0
public PositiveAtomicInteger(int value) {
this.value = new AtomicInteger(value);
}
public synchronized int incrementAndGet() {
int result = value.incrementAndGet();
//in case of integer overflow
if (result < 0) {
value.set(0);
return 0;
}
return result;
}
}
private static AtomicInteger count = new AtomicInteger(0);
count.set(0);
uniqueID = count.incrementAndGet();
Java's AtomicInteger offers public final boolean compareAndSet(int expect, int update). If false is returned, I would like to know what the value actually was at the time when the comparison failed. Is this possible in Java?
In .Net, there's public static int CompareExchange(ref int location1, int value, int comparand), which always returns the original value.
public int getAndCompareAndSet(AtomicInteger ai, int expected, int update) {
while (true) {
int old = ai.get();
if (old != expected) {
return old;
} else if (ai.compareAndSet(old, update)) {
return old;
}
}
}
(This sort of loop is how most operations on AtomicInteger are implemented: loops of get, do some logic, try compare-and-set.)
The API does not expose such a method. What's more, the Oracle implementation uses sun.misc.Unsafe to do the native CAS operation and that type doesn't expose it either.
One option is to just call get() if compareAndSet returned false. However, by the time you check it, the actual value of the AtomicInteger might have changed. There's not much you can do with it. This is true for Interlocked methods as well. You'd have to clarify what you want to do with that value to go any further.
When return value is not of interest, is there any (even irrelevant in practice) difference between AtomicInteger.getAndIncrement() and AtomicInteger.incrementAndGet() methods, when return value is ignored?
I'm thinking of differences like which would be more idiomatic, as well as which would put less load in CPU caches getting synchronized, or anything else really, anything to help decide which one to use more rationally than tossing a coin.
Since no answer to the actual question has been given, here's my personal opinion based on the other answers (thanks, upvoted) and Java convention:
incrementAndGet()
is better, because method names should start with the verb describing the action, and intended action here is to increment only.
Starting with verb is the common Java convention, also described by official docs:
"Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized."
The code is essentially the same so it does not matter:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
No, there's no difference (if you don't care about the return value).
The code of those methods (in the OpenJDK) differs only in that one uses return next and the other uses return current.
Both use compareAndSet under the hood with the exact same algorithm. Both need to know both the old and the new value.
Just want to add to existing answers: there could be very small non-noticeable difference.
If you look at this implementation:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
Note - both function call exactly the same function getAndAddInt, except +1 part, which means that in this implementation getAndIncrement is faster.
But, here is older implementation:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
The only difference is return variable, so both functions perform exactly the same.
Here I am giving an example. Hope it will clear your doubt.
Suppose I have a variable i as
AtomicInteger i = new AtomicInteger();
In this case:
i.getAndIncrement() <==> i++;
And
i.incrementAndGet() <==> ++i;
Please have a look of the below programs
public class Test1
{
public static void main(String[] args)
{
AtomicInteger i = new AtomicInteger();
System.out.println(i.incrementAndGet());
System.out.println(i);
}
}
**output
1
1
======================================**
public class Test2
{
public static void main(String[] args)
{
AtomicInteger i = new AtomicInteger();
System.out.println(i.getAndIncrement());
System.out.println(i);
}
}
**output
0
1
-------------**
Comment:
1) In the class Test1, incrementAndGet() will first increment the i value and then print.
2) In the class Test2, getAndIncrement() will first print the i value and then increment.
That's all.
I have been reading JCIP by Brian Goetz. He explains the implementation of a non-blocking counter using CAS instruction. I could not understand how the increment is happening using CAS instruction. Can anyone help me understand this.
public class CasCounter {
private SimulatedCAS value;
public int getValue() {
return value.get();
}
public int increment() {
int v;
do {
v = value.get();
}
while (v != value.compareAndSwap(v, v + 1));
return v + 1;
}
}
value.compareAndSwap(v, v + 1) is equivalent to the following, except that the entire block is atomic: (see compare-and-swap for details)
int old = value.val;
if (old == v) {
value.val = v + 1;
}
return old;
Now v = value.get() gets the current value of the counter, and if nobody else is trying to update the counter at the same time, old == v will be true, so the value is set to v+1 (i.e. it is incremented) and old is returned. The loop terminates since v == old.
Suppose someone else incremented the counter just after we did v = value.get(), then old == v would be false, and the method will immediately return old, which is the updated value. Since v != old now, the loop continues.
The compareAndSwap() method will perform the following operations atomically:
- determine if `value` is equal to `v`
- if so, it will set `value` to `v+1`
- it returns whatever `value` was when the method was entered (whether or not `value` was updated)
The caller can check to see if value was what they expected it to be when the called compareAndSwap(). If it was, then the caller knows it's been updated. If it wasn't what was expected, the caller knows that it wasn't updated, and will try again, using the 'new' current value of value as what's expected (that's what the loop is doing).
This way, the caller can know that the increment operation doesn't get lost by some other thread that tries to modify value at the same moment.