Firstly let me say that I am aware of this being a fairly common topic here but searching for it I couldn't quite find another question that clarifies the following situation. I am very sorry if this is a possible duplicate but here you go:
I am new to concurrency and have been given the following code in order to answer questions:
a) Why any other output aside from "00" would be possible?
b) How to amend the code so that "00" will ALWAYS print.
boolean flag = false;
void changeVal(int val) {
if(this.flag){
return;
}
this.initialInt = val;
this.flag = true;
}
int initialInt = 1;
class MyThread extends Thread {
public void run(){
changeVal(0);
System.out.print(initialInt);
}
}
void execute() throws Exception{
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start(); t2.start(); t1.join(); t2.join();
System.out.println();
}
For a) my answer would be the following: In the absence of any volatile / synchronization construct the compiler could reorder some of the instructions. In particular, "this.initialInt = val;" and "this.flag = true;" could be switched so that this situation could occur: The threads are both started and t1 charges ahead. Given the reordered instructions it first sets flag = true. Now before it reaches the now last statement of "this.initialInt = val;" the other thread jumps in, checks the if-condition and immediately returns thus printing the unchanged initialInt value of 1. Besides this, I believe that without any volatile / synchronization it is not for certain whether t2 might see the assignment performed to initialInt in t1 so it may also print "1" as the default value.
For b) I think that flag could be made volatile. I have learned that when t1 writes to a volatile variable setting flag = true then t2, upon reading out this volatile variable in the if-statement will see any write operations performed before the volatile write, hence initialInt = val, too. Therefore, t2 will already have seen its initialInt value changed to 0 and must always print 0.
This will only work, however, if the use of volatile successfully prevents any reordering as I described in a). I have read about volatile accomplishing such things but I am not sure whether this always works here in the absence of any further synchronized blocks or any such locks. From this answer I have gathered that nothing happening before a volatile store (so this.flag = true) can be reordered as to appear beyond it. In that case initialInt = val could not be moved down and I should be correct, right? Or not ? :)
Thank you so much for your help. I am looking forward to your replies.
This example will alway print 00 , because you do changeVal(0) before the printing .
to mimic the case where 00 might not be printed , you need to move initialInt = 1; to the context of a thread like so :
class MyThread extends Thread {
public void run(){
initialInt = 1;
changeVal(0);
System.out.print(initialInt);
}
}
now you might have a race condition , that sets initialInt back to 1 in thread1 before it is printed in thread2
another alternative that might results in a race-condition but is harder to understand , is switching the order of setting the flag and setting the value
void changeVal(int val) {
if(this.flag){
return;
}
this.flag = true;
this.initialInt = val;
}
There are no explicit synchronizations, so all kinds of interleavings are possible, and changes made by one thread are not necessarily visible to the other so, it is possible that the changes to flag are visible before the changes to initialInt, causing 10 or 01 output, as well as 00 output. 11 is not possible, because operations performed on variables are visible to the thread performing them, and effects of changeVal(0) will always visible for at least one of the threads.
Making changeVal synchronized, or making flag volatile would fix the issue. flag is the last variable changed in the critical section, so declaring it as volatile would create a happened-before relationship, making changes to initialInt visible.
Related
Should int a in this case be volatile to guarantee visibilty between threads?
private volatile static int a = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
a = 10;
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
System.out.println(a);
}
});
t1.start();
t2.start();
}
Output
10
happens-before is clearly defined in the language specification, start by reading that; to begin with.
Then to fully understand what is going on you need to know what Program order is, as well as synchronization order.
To put it very simplified, look at the below:
private volatile static int a = 0;
private static int b = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
b = 100;
a = 10;
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
if(a == 10){
System.out.println(b);
}
}
});
t1.start();
t2.start();
}
The only guarantee you have is that if, and only if, t2 prints something, it will always be 100. This is because t2 has seen a volatile write to a. That happens because a "happens-before" has been established, from the writing thread to the reading one, and every action done before a = 10 is guaranteed to be visible to the thread that has seen that a being 10.
Could you explain yourself a bit further on "happens-before"?
The most important thing to remember about "happens before" is that it's a transitive relation. That means, if the Java Language Spec (JLS) promises that A "happens before" B, and it promises that B "happens before" C, then you can infer a promise that A "happens before" C.
The JLS says that a write to some volatile variable "happens before" a subsequent read of the same variable.
Well Duh! Sounds obvious, doesn't it?
But it's not obvious because the JLS does not give the same guarantee for a non-volatile variable. If processor A writes the value 7 to a non-volatile int, and then some time later processor B writes 5, the JLS does not guarantee that some long time later, the final value of the variable will be 5. Processor B will see 5 (that's a different "happens before" promise, see below). Processor A could see 5 or 7, and any other processor could see 5 or 7 or whatever value the variable had initially (e.g., 0).
How the volatile promise helps
Suppose we have
volatile boolean flag = false;
/*non-volatile*/ int i = 0;
Suppose thread A does this:
i = 7;
flag = true;
And suppose thread B does this:
if (flag) {
System.out.println(i);
}
else {
System.out.println("Bleah!");
}
Thread B could print "7", or it could print "Bleah!" but because of the "happens before" guarantee, we absolutely know that thread B will never print "0". Why not?
Thread A set i = 7 before it set flag = true. The JLS guarantees that if a single thread executes one statement before it executes a second statement, then the first statment "happens before" the second statement. (That sounds stupendously obvious, but again, it shouldn't. A lot of things having to do with threads are not obvious.)
Thread B tests flag before it prints i. So *IF* thread A previously set flag=true then we know that i must equal 7: Transitivity: i=7 "happens before" flag=true, and the write to volatile flag, IF IT HAPPENED AT ALL, "happens before" a read of the same flag.
IF IT HAPPENED AT ALL
Data Races and Race Conditions
The biggest thing to remember is that when the JLS promises that A "happens before" B, they are not saying that A always actually does happen before B: They are saying that you can depend on that transitive relationship. They are saying that if A actually did happen before B, then all of the things that "happens before" A must also have actually happened before B.
The program can print "Bleah!" because nothing prevents thread B from testing the flag before thread A sets it. Some people call that a "data race." The two threads are "racing" to see which one gets to the flag first, and the outcome of the program depends on which thread wins that race.
When the correctness of a program depends on the outcome of a data race, some of us call that a "race condition," and that's a real headache. There's no guarantee that a program with a race condition won't do the right thing a thousand times during your testing, and then do the wrong thing when it matters most for your customer.
I have written a short program in order to check the effect of the race condition. Class Counter is given below. The class has two methods to update the counter instance variable c. On purpose, I added a random code in both methods , see related code variable i, to increase the probability of their interleaved execution when accessed by two threads.
In the main() method of my program, I put in a loop the following code
t1=new Thread() { public void run(){objCounter.increment();}};
t2=new Thread() { public void run(){objCounter.decrement();}};
t1.start();
t2.start();
try{
t1.join();
t2.join();
}
catch (InterruptedException IE) {}
Then I printed the different values of c in the objCount... Further to the expected values 1, 0, -1, the program displays also the unexpected values: -2,-1, -3, even 4
I sincerely can't see what threads interleaving will lead to the unexpected values given above. Ideally, I should look at the assembly code to see how the statements c++, and c-- got translated...regardless, I Think there is another reason behind the unexpected values.
class Counter{
private volatile int c=0;
public void increment(){
int i=9;
i=i+7;
c++;
i=i+3;
}
public void decrement() {
int i=9;
i=i+7;
c--;
i=i+3;
}
public int value(){ return c; }
}
Even if you marked an int as volatile, that kind of operations are not atomic. Try to replace your primitive int with a Thread Safe Class like:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html
Or just access it through a synchronyzed method.
I put in a loop the following code
You don't show reinitialization of the objCounter variable; this suggests that you're reusing the variable between loop iterations.
As such, you can get -2 from the situation resulting in -1 (e.g. Thread 1 read, Thread 2 read, T1 write, T2 write) happening twice.
In order to avoid reusing the state from previous runs, you should declare and initialize the objCounter variable inside the loop:
for (...) {
Counter objCounter = new Counter();
t1=new Thread() { public void run(){objCounter.increment();}};
t2=new Thread() { public void run(){objCounter.decrement();}};
// ... Start/join the threads.
}
It can't be declared before the loop and initialized inside the loop, because then it is not effectively final, which is required (that, or actual finality) to refer to it inside the anonymous classes of the threads.
On purpose, I added a random code in both methods , see related code variable i, to increase the probability of their interleaved execution when accessed by two threads.
As an aside, this your random code does nothing of the sort.
There is no requirement for Java to execute the statements in program order, only to appear to execute them in the program order from the perspective of the current thread.
These statements may be executed before or after the c++/--, if they are executed at all - they could simply be detected as useless.
You may as well just remove this code, it really only serves to obfuscate.
I am trying to see how volatile works here. If I declare cc as volatile, I get the output below. I know thread execution output varies from time to time, but I read somewhere that volatile is the same as synchronized, so why do I get this output? And if I use two instances of Thread1 does that matter?
2Thread-0
2Thread-1
4Thread-1
3Thread-0
5Thread-1
6Thread-0
7Thread-1
8Thread-0
9Thread-1
10Thread-0
11Thread-1
12Thread-0
public class Volexample {
int cc=0;
public static void main(String[] args) {
Volexample ve=new Volexample();
CountClass count =ve.new CountClass();
Thread1 t1=ve.new Thread1(count);
Thread2 t2=ve.new Thread2(count);
t1.start();
t2.start();
}
class Thread1 extends Thread{
CountClass count =new CountClass();
Thread1(CountClass count ){
this.count=count;
}
#Override
public void run() {
/*for(int i=0;i<=5;i++)
count.countUp();*/
for(int i=0;i<=5;i++){
cc++;
System.out.println(cc + Thread.currentThread().getName());
}
}
}
class Thread2 extends Thread {
CountClass count =new CountClass();
Thread2(CountClass count ){
this.count=count;
}
#Override
public void run(){
/*for(int i=0;i<=5;i++)
count.countUp();*/
for(int i=0;i<=5;i++){
cc++;
System.out.println(cc + Thread.currentThread().getName());
}
}
}
class CountClass{
volatile int count=0;
void countUp(){
count++;
System.out.println(count + Thread.currentThread().getName());
}
}
}
In Java, the semantics of the volatile keyword are very well defined. They ensure that other threads will see the latest changes to a variable. But they do not make read-modify-write operations atomic.
So, if i is volatile and you do i++, you are guaranteed to read the latest value of i and you are guaranteed that other threads will see your write to i immediately, but you are not guaranteed that two threads won't interleave their read/modify/write operations so that the two increments have the effect of a single increment.
Suppose i is a volatile integer whose value was initialized to zero, no writes have occurred other than that yet, and two threads do i++;, the following can happen:
The first thread reads a zero, the latest value of i.
The second threads reads a zero, also the latest value of i.
The first thread increments the zero it read, getting one.
The second thread increments the zero it read, also getting one.
The first thread writes the one it computed to i.
The second thread writes the one it computed to i.
The latest value written to i is one, so any thread that accesses i now will see one.
Notice that an increment was lost, even though every thread always read the latest value written by any other thread. The volatile keyword gives visibility, not atomicity.
You can use synchronized to form complex atomic operations. If you just need simple ones, you can use the various Atomic* classes that Java provides.
A use-case for using volatile would be reading/writing from memory that is mapped to device registers, for example on a micro-controller where something other than the CPU would be reading/writing values to that "memory" address and so the compiler should not optimise that variable away .
The Java volatile keyword is used to mark a Java variable as "being stored in main memory". That means, that every read of a volatile variable will be read from the computer's main memory, and not from the cache and that every write to a volatile variable will be written to main memory, and not just to the cache.
It guarantees that you are accessing the newest value of this variable.
P. S. Use larger loops to notice bugs. For example try to iterate 10e9 times.
I have two threads updating a shared int at the same time. Most of times, this code will print 0 and 1. But some times, it will print 0 and 0 (one update failed). If I make the int value volatile, will fix that update fail, once for all?
This is not a Home-Work question, really. I just wrote these code and this question, like if was, to clarify my understanding of Java Memory Model. I read this Article.
I know this code will be fixed in a synchronized way, but this is not the scope of question, is just about the volatile will fix or not, and why.
public class Testes{
public static int value = 0;
public static void main(String ... args) {
T t = new T();
T t2 = new T();
t.start();
t2.start();
}
}
class T extends Thread{
public void update(){
System.out.println(Testes.value++);
}
public void run(){
this.update();
}
}
If I make the int value volatile, will fix that update fail, once for all?
No. The issue you are seeing is almost certainly not related to memory inconsistency. The failure is because of atomicity. It is widely known ++ operator is not atomic (it is actually three operations). There is plenty of information you can read on about it.
Thanks to John for clarifying the same...
When you execute System.out.println(Testes.value++) what happens is
it is a postfix operation for increment...so the println is done
first and then value gets incremented...thats why you see 0 by
the first thread..but after the println is done its execution
the value is now 1 ..that is why the second thread shows 1 when
it prints the value ....
I have experience this weird behavior of volatile keyword recently. As far as i know,
volatile keyword is applied on to the variable to reflect the changes done on the data of
the variable by one thread onto the other thread.
volatile keyword prevents caching of the data on the thread.
I did a small test........
I used an integer variable named count, and used volatile keyword on it.
Then made 2 different threads to increment the variable value to 10000, so the end resultant should be 20000.
But thats not the case always, with volatile keyword i am getting not getting 20000 consistently, but 18534, 15000, etc.... and sometimes 20000.
But while i used synchronized keyword, it just worked fine, why....??
Can anyone please explain me this behaviour of volatile keyword.
i am posting my code with volatile keyword and as well as the one with synchronzied keyword.
The following code below behaves inconsistently with volatile keyword on variable count
public class SynVsVol implements Runnable{
volatile int count = 0;
public void go(){
for (int i=0 ; i<10000 ; i++){
count = count + 1;
}
}
#Override
public void run() {
go();
}
public static void main(String[] args){
SynVsVol s = new SynVsVol();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Total Count Value: "+s.count);
}
}
The following code behaves perfectly with synchronized keyword on the method go().
public class SynVsVol implements Runnable{
int count = 0;
public synchronized void go(){
for (int i=0 ; i<10000 ; i++){
count = count + 1;
}
}
#Override
public void run() {
go();
}
public static void main(String[] args){
SynVsVol s = new SynVsVol();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Total Count Value: "+s.count);
}
}
count = count + 1 is not atomic. It has three steps:
read the current value of the variable
increment the value
write the new value back to the variable
These three steps are getting interwoven, resulting in different execution paths, resulting in an incorrect value. Use AtomicInteger.incrementAndGet() instead if you want to avoid the synchronized keyword.
So although the volatile keyword acts pretty much as you described it, that only applies to each seperate operation, not to all three operations collectively.
The volatile keyword is not a synchronization primitive. It merely prevents caching of the value on the thread, but it does not prevent two threads from modifying the same value and writing it back concurrently.
Let's say two threads come to the point when they need to increment the counter, which is now set to 5. Both threads see 5, make 6 out of it, and write it back into the counter. If the counter were not volatile, both threads could have assumed that they know the value is 6, and skip the next read. However, it's volatile, so they both would read 6 back, and continue incrementing. Since the threads are not going in lock-step, you may see a value different from 10000 in the output, but there's virtually no chance that you would see 20000.
The fact that a variable is volatile does not mean every operation it's involved in is atomic. For instance, this line in SynVsVol.Go:
count = count + 1;
will first have count read, then incremented, and the result will then be written back. If some other thread will execute it at the same time, the results depend on the interleaving of the commands.
Now, when you add the syncronized, SynVsVol.Go executes atomically. Namely, the increment is done as a whole by a single thread, and the other one can't modify count until it is done.
Lastly, caching of member variables that are only modified within a syncronized block is much easier. The compiler can read their value when the monitor is acquired, cache it in a register, have all changes done on that register, and eventually flush it back to the main memory when the monitor is released. This is also the case when you call wait in a synchronized block, and when some other thread notifys you: cached member variables will be synchronized, and your program will remain coherent. That's guaranteed even if the member variable is not declared as volatile:
Synchronization ensures that memory writes by a thread before or
during a synchronized block are made visible in a predictable manner
to other threads which synchronize on the same monitor.
Your code is broken because it treats the read-and-increment operation on a volatile as atomic, which it is not. The code doesn't contain a data race, but it does contain a race condition on the int.