Reputation: 19
So my problem essentially is,that even though I use static volatile int variable for incrementation some of my data doesn't remain unique which would be my goal(I number my elements).
public class Producer implements Runnable{
private String str;
private Fifo f;
private int i;
private static volatile int n=0;
public Producer(String str,int i,Fifo f) ....
public void run() {
try {
this.go();
} catch (InterruptedException e) {
;
}
}
void go() throws InterruptedException {
while(true) {
Thread.sleep(i);
int l=n++;
String k=str+" "+l+" ";
f.put(k);
System.out.println("produced "+str+" "+l+" "+System.currentTimeMillis()%100000);
}
}
}
My problem is in the function go(). I number my elements, I have multiple Producer objects running as independent threads, but sometimes they act like they have no clue whether n has been updated or not so I get same indexes. Any ideas? (I get what could be the problem, but I have no clue how to solve it.)
Upvotes: 0
Views: 440
Reputation: 20185
There seems to be a misunderstanding as to what volatile
does. The keyword volatile
introduces happens-before semantics between writes and reads. It does not, however, make multiple operations atomic.
If we were to write the semantics of n++
"by hand" (please never do this, it is for explanatory purposes only), it would look something like that:
final int result;
n = (result = n) + 1;
Looking at this code, we see that we have to:
n
,result
,1
, andn
So we have multiple operations. If those operations are executed in parallel multiple times by different threads, then we can see a manifold of possible interweavings that lead to inconsistent data. For example, two threads could both read the (current) value of n
. Both would increment the value by one and both would write the new value back to n
. This means that two threads have executed the "increment", but the value of n
has only incremented by 1
instead of 2
.
We can use specialized classes - in this case AtomicInteger
- to avoid this problem. The usage looks something like this:
public class Producer implements Runnable {
...
private static final AtomicInteger n = new AtomicInteger(0);
...
void go() throws InterruptedException {
while(true) {
...
int l = n.getAndIncrement();
...
}
}
}
Upvotes: 5