Reputation: 3938
I am learning Thread Safe. I wrote an example and got a question.
First, my main() function is the same:
public class ThreadSafe {
public static void main(String[] args) {
System.out.println("Thread Safe");
SafeSharedRunnable r = new SafeSharedRunnable();
// Access the same resource
Thread tA = new Thread(r);
Thread tB = new Thread(r);
Thread tC = new Thread(r);
Thread tD = new Thread(r);
tA.start();
tB.start();
tC.start();
tD.start();
}
}
Then I have two versions Runnable in which synchronized() are placed in different places, and thus, one version works and one doesn't.
The working version:
public class SafeSharedRunnable implements Runnable {
int count = 5;
@Override
public void run() {
// Thread Safe, must be outside of while(), why?
synchronized ("") {
while (count > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
System.out.println("Current value is: " + count--);
}
}
}
}
The correct result:
run:
Thread Safe
Current value is: 5
Current value is: 4
Current value is: 3
Current value is: 2
Current value is: 1
BUILD SUCCESSFUL (total time: 0 seconds)
The non-working version:
public class SafeSharedRunnable implements Runnable {
int count = 5;
@Override
public void run() {
while (count > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
// Thread Safe
synchronized ("") {
System.out.println("Current value is: " + count--);
}
}
}
}
The wrong result:
run:
Thread Safe
Current value is: 5
Current value is: 4
Current value is: 2
Current value is: 3
Current value is: 1
Current value is: 0
Current value is: -1
Current value is: -2
BUILD SUCCESSFUL (total time: 0 seconds)
As you can see, different places of different synchronized() blocks result in different results. In my understanding, the key resource conflict should happen on this line of code:
System.out.println("Current value is: " + count--);
But why I must place synchronized() outside of while() block? Does that mean I should synchronize all the codes that contains variable "count"? Thanks for your detailed explanation.
I don't think this is a duplicate to race condition question, because I am not asking any general knowledge about multi-threading. Instead this is a detailed question about how multi threads enter a code flow.
Upvotes: 1
Views: 60
Reputation: 2406
The problem of your code is
// if four threads come here and now count is 1
synchronized ("") {
System.out.println("Current value is: " + count--);
}
The four threads will print count
in turn that caused the output 1 0 -1 -2
.
Try this code
synchronized("") {
if (count > 0) {
System.out.println("Current value is: " + count--);
}
}
Although your working version got the right output, you synchronized the while loop which means there is only one thread doing the whole things. This is not what a multithreading should do.
Upvotes: 1
Reputation: 2626
If you put synchronized ("")
inside while block then multiple thread same time see count =1 and all will enter inside while loop and decrease count and resulting wrong result.If you make count atomicinteger then it will be visible to all thread.
Upvotes: 0
Reputation: 5095
If the synchronized
only wraps the System.out.println
, then you're only guaranteeing the print statements to happen one at a time. So all of the threads could entire the while
immediately at the beginning of the run, before anything has been decremented. Once all the threads are inside the while
loop, they will run the print and decrement regardless of the count
.
However, if you wrap the while (count > 0) {
in the synchronized
as well, then only one thread can enter the while
at a time. This means each thread must check the count before performing the entire contents of the while loop, including the decrement.
Upvotes: 3