How does join() work? (Multithreading in Java) - java

I'm preparing for an exam and after going over some sample exercises (which have the correct answers included), I simply cannot make any sense out of them.
The question
(Multiple Choice): What are the some of the possible outcomes for the program below?
A)
Value is 1.
Value is 1.
Final value is 1.
B)
Value is 1.
Value is 1.
Final value is 2.
C)
Value is 1.
Final value is 1.
Value is 2.
D)
Value is 1.
Final value is 2.
Value is 2.
The Program
public class Thread2 extends Thread {
static int value = 0;
static Object mySyncObject = new Object();
void increment() {
int tmp = value + 1;
value = tmp;
}
public void run() {
synchronized(mySyncObject) {
increment();
System.out.print("Value is " + value);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread2();
Thread t2 = new Thread2();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.print("Final value is " + value);
}
}
The correct answers are: A), C) and D).
For case A) I don't understand how it's possible that both threads (after incrementing a seemingly static variable from within a synchronized block(!)) end up being set to 1 and the final value is thus 1 as well...?
Case C and D are equally confusing to me because I really don't understand how it's possible that main() finishes before both of the required threads (t1 and t2) do. I mean, their join() methods have been called from within the main function, so to my understanding the main function should be required to wait until both t1 and t2 are done with their run() method (and thus have their values printed)...??
It'd be awesome if someone could guide me through this.
Thanks in advance, much appreciated!
wasabi

There is something wrong with the answers or the question.
Your understanding of join() is correct. The "Final value is" message cannot be printed until both threads have completed. The calls to join() ensures this.
Furthermore, the increment() method is only called from within a synchronized block keyed on a static field. So there's no way this method could be called simultaneously by two threads. The "Value is" output is also within the same synchronized block. So there's no access to the value property from anywhere except within the synchronized block. Therefore, these operations are thread-safe.
The only possible output from this program is "Value is 1. Value is 2. Final value is 2." (In reality, there are no periods or spaces between the outputs - I'm just matching the format of the answers.)
I cannot explain why this matches none of the answers except that whoever wrote the question messed something up.

First i'd like to agree with rlibby. His answer can be proven by writing the program an present the output to the teacher.
If we omit that look at this:
its guaranteed to have two prints of 'Value is...'
it's not possible to print 'Value is 1' twice, since the increment is synchronized by a static object (this eliminates A and B)
the order of the print statements can not be forecasted
but: if we read a 'Final value is x' there must be a 'Value is X' too, no matter if before or after but it must exist

Related

Volatile Java reordering

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.

Unexpected values in a Concurrent program

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.

Will volatile fix this Multi-Thread Code?

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 ....

Java multi-threading threads terminating at random

While learning Java concurrency I ran into this behaviour which I can't explain:
public class ThreadInterferrence implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new ThreadInterferrence());
t.start();
append("1", 50);
t.join();
System.out.println(value);
}
private static String value = "";
public void run() {
append("2", 50);
}
private static void append(String what, int times) {
for (int i = 0; i < times; ++i) {
value = value + what;
}
}
}
Why does the program generate random Strings? More importantly why does the length of output vary? shouldn't it always be exactly 100 chars?
Output examples:
22222222222222222222222222222222222222222222222222
1111111111111111111111111111112121112211221111122222222222222
etc..
Reason is you have two threads.
Main thread which is appending to same value string
ThreadInterferrence Thread which is appending again to same value String.
It's Operating System (OS) who is scheduling which thread to run when and hence you see random output. So in your case, OS schedules your runnable to run for a time being which prints 1 and then tries to run main thread which in turn prints 2.
On the topic of your updated question (why does the length of output vary? shouldn't it always be exactly 100 chars?)
The behavior will be unpredictable, since the re-assignment of the new String is not atomic. Note that Strings are immutable and you keep reassinging a value to a variable. So what is happening is one thread gets the value, the other thread also gets the value, one thread adds a character and writes it again but so does the other thread with the old value. Now you're losing data because the update from one of the threads is lost.
In such a case you could use a StringBuffer which is thread-safe, or add synchronization which I'm sure you'll learn about.
[Question] More importantly why does the length of output vary?
[Answer] The variable "value" is being used by multiple threads (Main thread as well as the other thread). Hence the method which is used to change the state of the variable needs to be thread safe to control the final length. That is not the case here.

Thread value not cached by threads even without volatile?

class Counter
{
public int i=0;
public void increment()
{
i++;
System.out.println("i is "+i);
System.out.println("i/=2 executing");
i=i+22;
System.out.println("i is (after i+22) "+i);
System.out.println("i+=1 executing");
i++;
System.out.println("i is (after i++) "+i);
}
public void decrement()
{
i--;
System.out.println("i is "+i);
System.out.println("i*=2 executing");
i=i*2;
System.out.println("i is after i*2"+i);
System.out.println("i-=1 executing");
i=i-1;
System.out.println("i is after i-1 "+i);
}
public int value()
{
return i;
} }
class ThreadA
{
public ThreadA(final Counter c)
{
new Thread(new Runnable(){
public void run()
{
System.out.println("Thread A trying to increment");
c.increment();
System.out.println("Increment completed "+c.i);
}
}).start();
}
}
class ThreadB
{
public ThreadB(final Counter c)
{
new Thread(new Runnable(){
public void run()
{
System.out.println("Thread B trying to decrement");
c.decrement();
System.out.println("Decrement completed "+c.i);
}
}).start();
}
}
class ThreadInterference
{
public static void main(String args[]) throws Exception
{
Counter c=new Counter();
new ThreadA(c);
new ThreadB(c);
}
}
In the above code, ThreadA first got access to Counter object and incremented the value along with performing some extra operations. For the very first time ThreadA does not have a cached value of i. But after the execution of i++ (in first line) it will get cache the value. Later on the value is updated and gets 24. According to the program, as the variable i is not volatile so the changes will be done in the local cache of ThreadA,
Now when ThreadB accesses the decrement() method the value of i is as updated by ThreadA i.e. 24. How could that be possible?
Assuming that threads won't see each updates that other threads make to shared data is as inappropriate as assuming that all threads will see each other's updates immediately.
The important thing is to take account of the possibility of not seeing updates - not to rely on it.
There's another issue besides not seeing the update from other threads, mind you - all of your operations act in a "read, modify, write" sense... if another thread modifies the value after you've read it, you'll basically ignore it.
So for example, suppose i is 5 when we reach this line:
i = i * 2;
... but half way through it, another thread modifies it to be 4.
That line can be thought of as:
int tmp = i;
tmp = tmp * 2;
i = tmp;
If the second thread changes i to 4 after the first line in the "expanded" version, then even if i is volatile the write of 4 will still be effectively lost - because by that point, tmp is 5, it will be doubled to 10, and then 10 will be written out.
As specified in JLS 8.3.1.4:
The Java programming language allows threads to access shared
variables (ยง17.1). As a rule, to ensure that shared variables are
consistently and reliably updated, a thread should ensure that it has
exclusive use of such variables by obtaining a lock that,
conventionally, enforces mutual exclusion for those shared variables........A field may be
declared volatile, in which case the Java Memory Model ensures that
all threads see a consistent value for the variable
Although not always but there is still a chance that the shared values among threads are not consistenly and reliably updated, which would lead to some unpredictable outcome of program. In code given below
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
If, one thread repeatedly calls the method one (but no more than Integer.MAX_VALUE times in all), and another thread repeatedly calls the method two then method two could occasionally print a value for j that is greater than the value of i, because the example includes no synchronization and, the shared values of i and j might be updated out of order.
But if you declare i and j to be volatile , This allows method one and method two to be executed concurrently, but guarantees that accesses to the shared values for i and j occur exactly as many times, and in exactly the same order, as they appear to occur during execution of the program text by each thread. Therefore, the shared value for j is never greater than that for i,because each update to i must be reflected in the shared value for i before the update to j occurs.
Now i came to know that common objects (the objects that are being shared by multiple threads) are not cached by those threads. As the object is common, Java Memory Model is smart enough to identify that common objects when cached by threads could produce surprising results.
How could that be possible?
Because there is nowhere in the JLS that says values have to be cached within a thread.
This is what the spec does say:
If you have a non-volatile variable x, and it's updated by a thread T1, there is no guarantee that T2 can ever observe the change of x by T1. The only way to guarantee that T2 sees a change of T1 is with a happens-before relationship.
It just so happens that some implementations of Java cache non-volatile variables within a thread in certain cases. In other words, you can't rely on a non-volatile variable being cached.

Categories