AtomicInteger calculation in a loop - java

public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
I found that the increment method works within a loop block. Why can't we just calculate a result without any looping? What is sence on it?

If another thread came along and changed the value of AtomicInteger between int current = get() and compareAndSet(current, next), then the compareAndSet call would fail. Using a loop ensures that this possibility will never happen.

It's possible for the call to compareAndSet to return false if another thread increments or otherwise modifies the AtomicInteger at the same time that the current thread is incrementing the AtomicInteger
current thread calls current = get()
another thread modifies the AtomicInteger
current thread calls next = current + 1
current thread calls if(compareAndSet(current, next))
On step 4, the call to compareAndSet will return false and will leave the AtomicInteger unchanged because current will not match the current value of the AtomicInteger (due to another thread having modified it on step 2); therefore the method loops and tries again

compareAndSet might fail if another thread is updating. The for(;;) is a bit weird, I would have gone for while(true).
This is called optimistic locking.

Consider you have three threads T1, T2, T3 running
T1: int current = get(); == 0
T2: int current = get(); == 0
T3: int current = get(); == 0
T3: int next = current + 1;
T1: int next = current + 1;
T2: int next = current + 1;
T2: if (compareAndSet(current, next)) // true
T2: return current;
T3: if (compareAndSet(current, next)) // false
T1: if (compareAndSet(current, next)) // false
T1 and T3 need to try again, and only one might succeed the second time.

Related

Scala thread safety

I'm running this code in Scala:
def injectFunction(body: =>Unit): Thread = {
val t = new Thread {
override def run() = body
}
t
}
private var counter: Int = 0
def increaseCounter(): Unit = this.synchronized {
//putting this as synchronized doesn't work for some reason..
counter = counter + 1
counter
}
def printCounter(): Unit = {
println(counter)
}
val t1: Thread = injectFunction(increaseCounter())
val t2: Thread = injectFunction(increaseCounter())
val t3: Thread = injectFunction(printCounter())
t1.start()
t2.start()
t3.start()
This prints out 1 most of the time, though sometimes 2 and 0 a few times. Shouldn't the this.synchronized before the increaseCounter() method ensure that it's thread safe, and print 2 every time? I've also tried adding this.synchronized in the definition of printCounter(), with no luck.
Very entertaining example! It's so broken that it actually fails at failing to fail:
It was already failing right from the beginning, because it started with the wrong assumption that the synchronized keyword would somehow force the t3 to execute last. But that's simply not the case, the synchronized has nothing to do with the order in which the threads are executed. The threads can still run in arbitrary order, the synchronized merely ensures that they don't enter the synchronized block simultaneously.
Then it additionally fails at generating a random 0 / 1 / 2 output, because there is no synchronized block around the counter in the println, i.e. there is no actual guarantee that the printing thread will see the random changes made by the two other threads. As it is, the printing thread had every right to print 0, without being obliged to do so.
The statements that are executed in the initializer of the object attempt to acquire this in this.synchronized. If one additionally adds tN.join() into the initializer, everything freezes with a deadlock (because the initialization cannot finish before t1, t2, t3 can join, and they cannot join before they can enter a this.synchronized, and they cannot enter this.synchronized before the initialization has unlocked this).
Here is the example that fixes all three problems:
object Example {
def injectFunction(body: =>Unit): Thread = {
val t = new Thread {
override def run() = body
}
t
}
private var counter: Int = 0
def increaseCounter(): Unit = {
//
Thread.sleep(util.Random.nextInt(1000))
this.synchronized {
counter += 1
}
}
def printCounter(): Unit = {
Thread.sleep(util.Random.nextInt(1000))
println("Random state: " + this.synchronized { counter })
}
def main(args: Array[String]): Unit = {
val t1: Thread = injectFunction(increaseCounter())
val t2: Thread = injectFunction(increaseCounter())
val t3: Thread = injectFunction(printCounter())
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
println("Final state: " + counter)
}
}
Now this will indeed randomly output
Random state: 0
Final state: 2
or
Random state: 1
Final state: 2
or
Random state: 2
Final state: 2
The crucial differences to your code are:
random sleeps make the parallelism at least somewhat visible. Without this, you might get 2 & 2 repeatedly.
the reading access to counter in println(counter) must also be synchronized
if you want to demonstrate that the final state of the counter is 2, you have to wait for all three threads to join.
All the statements are in the main, so that the object can be initialized correctly.

Multi-threading State in Java with Semaphores

I have a question about using Semaphores in multithreaded Java code.
There are three threads being fired asynchronously. One of them calls zero(), the other calls even(), and the last one calls odd(). "0102" is the correct output.
Semaphore zero = new Semaphore(1);
Semaphore odd = new Semaphore(0);
Semaphore even = new Semaphore(0);
public void zero(IntConsumer printNumber) throws InterruptedException {
for(int i = 0; i < n; i++) {
zero.acquireInterruptibly();
printNumber.accept(0);
if(i % 2 == 0) {
odd.release();
} else {
even.release();
}
}
}
public void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 2; i <= n; i += 2) {
even.acquire();
printNumber.accept(i);
zero.release();
}
}
public void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i += 2) {
odd.acquire();
printNumber.accept(i);
zero.release();
}
}
In the code shown above, the first function that will run is function 'zero' because only that lock is able to be required. Then, the function 'odd' will be able to be called from another thread since it's lock has been released and therefore able to be acquired.
Two questions:
1) Can the same thread that acquired the 'zero' lock reenter the for loop before the lock has been released by the function 'odd'
2) How is the state of the for loop preserved after a thread has been switched out?
Edit: In understanding semaphores a bit more, I know realize that regardless of whether the fact that the thread had acquired the semaphore before, it can not run unless the number of permits available for that sempaphore is greater than 0. Therefore, until the number of permits available is greater than 0, the function will not be able to run until a release of that semaphore occurs so that the number of permits available is greater than 0. The question remains though, how is that state of the for loop preserved so that when I reenter the for loop, I do not start back at the initial 'i' value.

Java Multi-threading : Unexpected result

I am working on a Enterprise application. I am facing some issues while running application in multithreaded environment. I am writing a program in which there is a variable whose value is getting updated(incremented) at very fast rate (for example 10000 updates/persecond). A loop runs for certain iterations and the value of the variable is incremented and stored in HashMap. Once the loop terminates and value the variable in HashMap is printed. I am getting unexpected value of the variable.
Here is demo program (Please read comments for better understanding) :
class test implements Runnable {
static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
static AtomicInteger value_to_be_incremented_stored = new AtomicInteger(0); // variable whose value to be updated
static AtomicInteger i = new AtomicInteger(0); // this runs the loop
#Override
public void run() {
for (i.set(0); i.get() < 100000; i.incrementAndGet()) {
/*
This loop should run 100000 times and when loop terminates according to me value of variable
"value_to_be_incremented_stored" should be 100000 as its value is incremented
100000 times the loop also runs 100000 times.
*/
System.out.println("Thread > " + Thread.currentThread() + " " + value_to_be_incremented_stored.incrementAndGet());
map.put("TC", value_to_be_incremented_stored.intValue());
}
System.out.println("Output by Thread " + Thread.currentThread() + " " + map.toString());
}
public static void main(String[] args) {
test t1 = new test();
Thread thread1 = new Thread(t1);
thread1.setName("Thread 1");
Thread thread2 = new Thread(t1);
thread2.setName("Thread 2");
Thread thread3 = new Thread(t1);
thread3.setName("Thread 3");
Thread thread4 = new Thread(t1);
thread4.setName("Thread 4");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
Output (it varies) :
Issue :
I am running loop for 100000 times (i.get() < 100000) then how come value of variable value_to_be_incremented_stored becomes more than 100000.
I found three defects. One there is a race condition in the for loop between the point where you compare the loop counter, and where you increment it. You should do this in one step to get an atomic operation:
for ( ; i.incrementAndGet() < 100000; ) {
The other is there is also a race condition between the increment of your counter, and placing it in the map. Even though you increment these in series, any thread could be have a different value internally (it's at a different point in the loop) and it could put a previous value in the global map. You need atomicity here to to make sure the value you increment is the value you place in the loop.
synchronized( lock ) {
value_to_be_incremented_stored.incrementAndGet();
map.put("TC", value_to_be_incremented_stored.intValue());
}
Finally for some reason the < comparison produces a value of 99999 for me. I had to use <= to fix it.
(And as we discussed in the comments, setting i.set(0) at the start of each for loop doesn't work for fairly obvious reasons. Four defects, I guess.)
class ThreadTestX implements Runnable {
static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
static AtomicInteger value_to_be_incremented_stored = new AtomicInteger(0); // variable whose value to be updated
static AtomicInteger i = new AtomicInteger(0); // this runs the loop
static final Object lock = new Object();
#Override
public void run() {
for ( ; i.incrementAndGet() <= 100000; ) {
/*
This loop should run 100000 times and when loop terminates according to me value of variable
"value_to_be_incremented_stored" should be 100000 as its value is incremented
100000 times the loop also runs 100000 times.
*/
synchronized( lock ) {
value_to_be_incremented_stored.incrementAndGet();
// System.out.println("Thread > " + Thread.currentThread() +
// " " + value_to_be_incremented_stored.get());
map.put("TC", value_to_be_incremented_stored.intValue());
}
}
System.out.println("Output by Thread " + Thread.currentThread()
+ " " + map.toString());
}
public static void main(String[] args) {
ThreadTestX t1 = new ThreadTestX();
Thread thread1 = new Thread(t1);
thread1.setName("Thread 1");
Thread thread2 = new Thread(t1);
thread2.setName("Thread 2");
Thread thread3 = new Thread(t1);
thread3.setName("Thread 3");
Thread thread4 = new Thread(t1);
thread4.setName("Thread 4");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
Output:
run:
Output by Thread Thread[Thread 4,5,main] {TC=100000}
Output by Thread Thread[Thread 3,5,main] {TC=100000}
Output by Thread Thread[Thread 1,5,main] {TC=100000}
Output by Thread Thread[Thread 2,5,main] {TC=100000}
BUILD SUCCESSFUL (total time: 0 seconds)
Afterthoughts: And in spite of getting marked correct, I'm not sure I was correct. The problem here is that you are trying to keep three things in sync: the loop counter i, the value to be incremented, and the map. Allowing any of these to be executed outside of a synchronized block may invite them to be in an unexpected state. I think the following may be safer:
#Override
public void run() {
for ( ;; ) {
synchronized( lock ) {
if( i.incrementAndGet() <= 100000 ) {
value_to_be_incremented_stored.incrementAndGet();
map.put("TC", value_to_be_incremented_stored.intValue());
}
else
break;
}
}
System.out.println("Output by Thread " + Thread.currentThread()
+ " " + map.toString());
}
This removes the need for declaring the variables as AtomicInteger, but I don't see how else you ensure that their values don't change (due to some other thread) as that loop executes.
Your "demo program" suffers from two simultaneous defects.
Defect #1 is the i.set( 0 ) pointed out by tsolakp. You say you fixed that but you are still getting a value of more than 100000. I also tried it and indeed, the final value is still larger than 100000.
I modified the program to be able to create an arbitrary number of threads, and I tried with 3, 10, and 20 threads. I got a final number of 100003, 100009, and 100019 respectively. See a pattern? So:
Defect #2 is that on the last iteration, when the value of i is 99999, the expression i.get() < 100000 is true for all threads, so all threads proceed to execute once more. The i.incrementAndGet() clause is visually sitting right next to i.get() < 1000000; but it does not get executed until the end of the loop.
So, all threads get a chance to increment i once more after the last iteration.
Everytime a new thread enters the run method it will reset your i count to zero via the first statement in the for loop by calling i.set(0).
Update: Next step after fixing reset issue, is to step through the code and see how the threads will behave.
Lets say three threads get inside the for loop while the fourth thread increments i. What will happen is that value_to_be_incremented_stored will increment 3 times and i only one time.

Data Races in an AtomicIntegerArray

In the code below:
I am updating num[1]=0 of an AtomicIntegerArray num 1000 times each in 2 threads.
At the end of the 2 threads in main thread ;shouldn't the value of num[1] be 2000 as there shouldn't be data races in an AtomicIntegerArray .
However I get random values < 2000. Could someone tell me why?
Code:
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicIntegerArr {
private static AtomicIntegerArray num= new AtomicIntegerArray(2);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyRun1());
Thread t2 = new Thread(new MyRun2());
num.set(0, 10);
num.set(1, 0);
System.out.println("In Main num before:"+num.get(1));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("In Main num after:"+num.get(1));
}
static class MyRun1 implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
num.set(1,num.get(1)+1);
}
}
}
static class MyRun2 implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
num.set(1,num.get(1)+1);
}
}
}
}
Edit: Adding num.compareAndSet(1, num.get(1), num.get(1)+1); instead of num.set(1,num.get(1)+1); doesnt work either.
I get random values < 2000. Could someone tell me why?
This is called the lost-update problem.
Because, in the following code:
num.set(1, num.get(1) + 1);
Although each individual operation involved is atomic, the combined operation is not. The single operations from the two threads can interleave, causing updates from one thread to be overwritten with stale value by another thread.
You can use compareAndSet to solve this problem, but you have to check whether the operation is successful, and do it again when it fails.
int v;
do {
v = num.get(1);
} while (!num.compareAndSet(1, v, v+1));
There's also a method for exactly this purpose:
num.accumulateAndGet(1, 1, (x, d)->x+d);
accumulateAndGet(int i, int x, IntBinaryOperator accumulatorFunction)
Atomically updates the element at index i with the results of applying the given function to the current and given values, returning the updated value. The function should be side-effect-free, since it may be re-applied when attempted updates fail due to contention among threads. The function is applied with the current value at index i as its first argument, and the given update as the second argument.
This is a classic race condition. Any time you have a fetch, an operation, and a put, your code is racy.
Consider two threads, both executing num.set(1,num.get(1)+1) at roughly the "same time." First, let's break down what the expression itself is doing:
it fetches num.get(1); let's call this x
it adds 1 to that; let's call this y
it puts that sum in at `num.set(1, y);
Even though the intermediate values in your expression are just values on the stack, and not explicit variables, the operation is the same: get, add, put.
Okay, so back to our two threads. What if the operations are ordered like this?
inital state: n[1] = 5
Thread A | Thread B
========================
x = n[1] = 5 |
| x = n[1] = 5
| y = 5 + 1 = 6
y = 5 + 1 = 6 |
n[1] = 6 |
| n[1] = 6
Since both threads fetched the value before either thread put its added value, they both do the same thing. You have 5 + 1 twice, and the result is 6, not 7!
What you want is getAndIncrement(int idx), or one of the similar methods that does the get, adding, and putting atomically.
These methods can actually all be built on top of the compareAndSet method you identified. But to do that, you need to do the increment within a loop, trying until the compareAndSet returns true. Also, for that to work, you have store that initial num.get(1) value in a local variable, rather than fetching it a second time. In effect, this loop says "keep trying the get-add-put logic until it works without anyone else having raced between the operations." In my example above, Thread B would have noticed that compareAndSet(1, 5, 6) fails (since the actual value at that time is 6, not 5 as expected), and thus retried. This is in fact what all of those atomic methods, like getAndIncrement, do.

Implementation of the addAndGet in AtomicInteger class

I was going through the Java(Java 6) souce code for the addAndGet method in the AtomicInteger class.
The corresponding code was as follows:
public final int addAndGet(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return next;
}
}
The compareAndSet method calls a native method to carry out the assignment.
There are mainly two questions:
How does the infinite loop help ?
What could be the scenarios, under which the "if
(compareAndSet(current, next))" condition could return a false ? In
such a case, the code might run into an infinite loop. If it is
guaranteed that compareAndSet will always return a "true", then can
we not do away with this check altogether ?
Similar doubts are with the decrementAndGet, getAndDecrement, getAndAdd methods as well.
How does the infinite loop help ?
This means: retry until it worked.
Without the loop, it may not succeed the first time around (see below).
What could be the scenarios, under which the "if (compareAndSet(current, next))" condition could return a false ?
That happens if two threads try to modify the value at the same time. One of them will get there first. The other one will fail.
Imagine two threads (A and B) trying to increment from 5 to 6
A: int current = get(); // current = 5
B: int current = get(); // current = 5
B: int next = current + delta; // next = 6
B: if (compareAndSet(current, next)) // OK
return next;
A: int next = current + delta; // next = 6
A: if (compareAndSet(current, next))
// fails, because "current" is still 5
// and that does not match the value which has been changed to 6 by B
Note that the whole point of this class is to avoid locks. So instead, you have this "optimistic currency control": Just assume no one else is working on the data at the same time, and if that turns out to be wrong, rollback and retry.
In such a case, the code might run into an infinite loop
Not really. It can only fail once for every other thread that does something to the value.
Thread A from above in the second iteration:
A: int current = get(); => current now 6
A: int next = current + delta; => next = 7
A: if (compareAndSet(current, next)) => now OK
You could conceivably end up with one thread waiting forever if other threads incessantly update the value, but only then. To avoid that, you'd need some definition of "fairness" (which some other tools in the concurrency package support).

Categories

Resources