This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 8 years ago.
Using a basic example to illustrate my problem I have 2 near-identical bits of code.
This code causes the while loop to run infinitely.
private boolean loadAsset() {
new Thread(new Runnable() {
#Override
public void run() {
// Do something
loaded = true;
}
}).start();
while (!loaded) {
// System.out.println("Not Loaded");
}
System.out.println("Loaded");
return false;
}
This code however (i.e. doing something in the while loop) causes the loaded variable to be successfully evaluated and allows the while loop to break and method to finish.
private boolean loadAsset() {
new Thread(new Runnable() {
#Override
public void run() {
// Do something
loaded = true;
}
}).start();
while (!loaded) {
System.out.println("Not Loaded");
}
System.out.println("Loaded");
return false;
}
Can anyone explain to me why this is?
The first loop only "appears" to run infinitely. You're actually running an "active wait", burning 100% of your CPU, such that your OS or JVM can't make a context switch and let the other thread run.
With the System.out.println() on the other hand, there is I/O involved, resulting in a somewhat "inactive wait". The OS or JVM can switch contexts and the other thread starts.
If you'd run your first program for 10 hours, I'm sure the loop would break eventually
Check that 'loaded' is definitely declared as volatile.
Explanation: if a variable is read and/or written by multiple threads, then you need to take appropriate thread-safety measures. One such thread-safety measure is volatile, which is suitable for primitive values (or object references) which are read or written as 'simple' actions with the value written on a given occasion not depending on the previously read value. For more information, I have an article about volatile on my web site (along with other information about thread-safety generally) that may be of help.
If loaded is not volatile, the JIT is free to optimise it by placing it in a register and not loading it from memory every time. In the second case, the loop is too complex for the JIT to assume it doesn't need to load loaded each time.
Note: its is the JIT not the javac compiler which optimises the code.
Read up on Memory Consistency Errors. Basically, different threads have inconsistent views of what should be the same data. In order to resolve this, read up on Synchronization. Or simply declare loaded as volatile, since its value is only being written by a single thread.
I believe you are experiencing a Busy Wait with the empty loop, which will never sleep. Thus, your Thread to set loaded to true never runs.
Related
I've encountered this code in a book. It states NoVisibility could loop forever because the value of ready might never become
visible to the reader thread.
I'm confused by this statement. In order for the loop to run forever, ready must always be false, which is the default value. This means it must fail at executing ready = true; because the reader thread will always read the ready variable from memory. the assignment happens in CPU and it must have some problem in flushing the data back to Main Memory. I think I need some explanation on a situation how it can fail, or I may have missed some other part.
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
Your understanding is flawed. You are assuming that Java will behave intuitively here. In fact, it may not. And, indeed, the Java Language specification allows non-intuitive behavior if you don't follow the rules.
To be more specific, in your example it is NOT GUARANTEED that the second thread will see the results of the first thread's assignment to ready1. This is due to such things as:
The compiler caching the value of ready in a register in the first or second thread.
The compiler not including instructions to force the write to be flushed from one core's memory cache to main memory, or similar.
If you want a guarantee that the second thread will see the result of the write then either reads and writes of ready by the two threads must be (properly) synchronized, or the ready variable must be declared to be volatile.
So ...
This means it must fail at executing ready = true; because the reader thread will always read the ready variable from memory.
is incorrect. The "because" is not guaranteed by the Java language specification in this example.
Yes. It is nonintuitive. Relying on your intuition based on your understanding of single-threaded programs is not reliable. If you want to want to understand what is and is not guaranteed, please study the specification of the "Java Memory Model" in Section 17.4 of the JLS.
In short, the book is correct.
1 - It might see the results immediately, or after a short or long delay. Or it might never see them. And the behavior is liable to vary from one system to the next, and with versions of the Java platform. So your program that (by luck) works all of the time on one system may not always work on another system.
The value of ready may be updated but the other thread may never know about it. There you need volatile variables! A thread assumes that the variable is only used by this and only thread. So, it reads its value from the stack that it created.
private static volatile boolean ready;
What volatile does is that it says to your program to ready from the memory, not from the stack.
Actually what jvm does is it translates:
while(flag){...}
To:
if(flag){
while(true){
}
The stack is created when the thread is created. It collectes the values of the variables in order to use them later.
This is what I have understand, correct me if I am wrong!
I am new to Java, I am currently learning about volatile. Say I have the following code:
public class Test
{
private static boolean b = false;
public static void main(String[] args) throws Exception
{
new Thread(new Runnable()
{
public void run()
{
while(true)
{
b = true;
}
}
}).start();
// Give time for thread to start
Thread.sleep(2000);
System.out.println(b);
}
}
Output:
true
This code has two threads (the main thread and another thread). Why is the other thread able to modify the value of b, shouldn't b be volatile in order for this to happen?
The volatile keyword guarantees that changes are visible amongst multiple threads, but you're interpreting that to mean that opposite is also true; that the absence of the volatile keyword guarantees isolation between threads, and there's no such guarantee.
Also, while your code example is multi-threaded, it isn't necessarily concurrent. It could be that the values were cached per-thread, but there was enough time for the JVM to propagate the change before you printed the result.
You are right that with volatile, you can ensure/guarantee that your 2 threads will see the appropriate value from main memory at all times, and never a thread-specific cached version of it.
Without volatile, you lose that guarantee. And each thread is working with its own cached version of the value.
However, there is nothing preventing the 2 threads from resynchronizing their memory if and when they feel like it, and eventually viewing the same value (maybe). It's just that you can't guarantee that it will happen, and you most certainly cannot guarantee when it will happen. But it can happen at some indeterminate point in time.
The point is that your code may work sometimes, and sometimes not. But even if every time you run it on your personal computer, is seems like it's reading the variable properly, it's very likely that this same code will break on a different machine. So you are taking big risks.
Please look at this code(taken from Effective Java book)
import java.util.concurrent.TimeUnit;
public class Main {
private static boolean stopReq;
public static void main(String[] args) throws InterruptedException {
Thread bgw = new Thread(new Runnable()
{
public void run(){
int i = 0;
while(!stopReq){ i++;}
}
});
bgw.start();
TimeUnit.SECONDS.sleep(1);
stopReq = true;
}
}
Why does the bgw thread get stuck in an infinite loop? Is it caching it's own copy of stopReq when it reached the loop? So it never sees the updated value from the other thread?
I understand the solution to this problem would be synchronizing or a volatile variable, but I am curious to why this current implementation doesn't work.
thanks
Your explanation is right.
The compiler detects than stopReq is never modified in the loop and since it is not volatile, optimizes the while(!stopReq) instruction to while(true).
Even though the value changes later, the thread does not even read it any more.
You should read more about Java Memory Model to better understand all the implications.
Shortly, the stopReq variable not being volatile or included in a synchronized block gives the VM freedom to use an optimized local storage (eg. registers etc) which is not guaranteed to propagate changes immediately across the threads.
When you declare the variable as volatile the VM will make sure that after each variable write a "memory write barrier" is inserted which will force all the local changes to be spilled to the real memory location thus making it visible to all the other threads (the same barrier is placed at the end of a synchronized block eg.)
To be very specific about your query, to take full advantage of the performance of modern multiprocessor hardware, in absence of synchronization, JVMs allowed to permit compiler to re-order operations and cache values in registers and in processor specific caches.
As main thread writes to stopReq without synchronization so because of reordering and caching the BTW thread might never see the written value and loop forever.
When you use synchronization or volatile they guarantee VISIBILITY and force compiler not to cache and flush changes to main memory.
Make stopReq to true, then it will be stopped. You are again setting the stopReq to false, due to that while loop condition is true always and it is in infinite loop.
I tested this out, and no, the variables are the same. The example also compiles for me.
The error is here:
Your while loop goes on, as long as !stopReq is true, that means stopReq is false.
And after 1 sec you set stopReq to false - this changes nothing. If you set it to true, !stopReq will become false and your loop will end.
So I've been reading on concurrency and have some questions on the way (guide I followed - though I'm not sure if its the best source):
Processes vs. Threads: Is the difference basically that a process is the program as a whole while a thread can be a (small) part of a program?
I am not exactly sure why there is a interrupted() method and a InterruptedException. Why should the interrupted() method even be used? It just seems to me that Java just adds an extra layer of indirection.
For synchronization (and specifically about the one in that link), how does adding the synchronize keyword even fix the problem? I mean, if Thread A gives back its incremented c and Thread B gives back the decremented c and store it to some other variable, I am not exactly sure how the problem is solved. I mean this may be answering my own question, but is it supposed to be assumed that after one of the threads return an answer, terminate? And if that is the case, why would adding synchronize make a difference?
I read (from some random PDF) that if you have two Threads start() subsequently, you cannot guarantee that the first thread will occur before the second thread. How would you guarantee it, though?
In synchronization statements, I am not completely sure whats the point of adding synchronized within the method. What is wrong with leaving it out? Is it because one expects both to mutate separately, but to be obtained together? Why not just have the two non-synchronized?
Is volatile just a keyword for variables and is synonymous with synchronized?
In the deadlock problem, how does synchronize even help the situation? What makes this situation different from starting two threads that change a variable?
Moreover, where is the "wait"/lock for the other person to bowBack? I would have thought that bow() was blocked, not bowBack().
I'll stop here because I think if I went any further without these questions answered, I will not be able to understand the later lessons.
Answers:
Yes, a process is an operating system process that has an address space, a thread is a unit of execution, and there can be multiple units of execution in a process.
The interrupt() method and InterruptedException are generally used to wake up threads that are waiting to either have them do something or terminate.
Synchronizing is a form of mutual exclusion or locking, something very standard and required in computer programming. Google these terms and read up on that and you will have your answer.
True, this cannot be guaranteed, you would have to have some mechanism, involving synchronization that the threads used to make sure they ran in the desired order. This would be specific to the code in the threads.
See answer to #3
Volatile is a way to make sure that a particular variable can be properly shared between different threads. It is necessary on multi-processor machines (which almost everyone has these days) to make sure the value of the variable is consistent between the processors. It is effectively a way to synchronize a single value.
Read about deadlocking in more general terms to understand this. Once you first understand mutual exclusion and locking you will be able to understand how deadlocks can happen.
I have not read the materials that you read, so I don't understand this one. Sorry.
I find that the examples used to explain synchronization and volatility are contrived and difficult to understand the purpose of. Here are my preferred examples:
Synchronized:
private Value value;
public void setValue(Value v) {
value = v;
}
public void doSomething() {
if(value != null) {
doFirstThing();
int val = value.getInt(); // Will throw NullPointerException if another
// thread calls setValue(null);
doSecondThing(val);
}
}
The above code is perfectly correct if run in a single-threaded environment. However with even 2 threads there is the possibility that value will be changed in between the check and when it is used. This is because the method doSomething() is not atomic.
To address this, use synchronization:
private Value value;
private Object lock = new Object();
public void setValue(Value v) {
synchronized(lock) {
value = v;
}
}
public void doSomething() {
synchronized(lock) { // Prevents setValue being called by another thread.
if(value != null) {
doFirstThing();
int val = value.getInt(); // Cannot throw NullPointerException.
doSecondThing(val);
}
}
}
Volatile:
private boolean running = true;
// Called by Thread 1.
public void run() {
while(running) {
doSomething();
}
}
// Called by Thread 2.
public void stop() {
running = false;
}
To explain this requires knowledge of the Java Memory Model. It is worth reading about in depth, but the short version for this example is that Threads have their own copies of variables which are only sync'd to main memory on a synchronized block and when a volatile variable is reached. The Java compiler (specifically the JIT) is allowed to optimise the code into this:
public void run() {
while(true) { // Will never end
doSomething();
}
}
To prevent this optimisation you can set a variable to be volatile, which forces the thread to access main memory every time it reads the variable. Note that this is unnecessary if you are using synchronized statements as both keywords cause a sync to main memory.
I haven't addressed your questions directly as Francis did so. I hope these examples can give you an idea of the concepts in a better way than the examples you saw in the Oracle tutorial.
I change a value that is used to determine when a while-loop terminates in a seperate thread.
I don't want to know how to get this working. If I access the variable test only through synchronized getters/setters it works as expected..
I would have expected, if some read/write commands are lost due to concurrency the program sometimes does not terminate, but it never does. Thats what confuses me..
I would like to know why the program never terminates, without the print-command. And I would like to understand why the print-command changes anything..
public class CustomComboBoxDemo {
public static boolean test = true;
public static void main(String[] args) {
Thread user =new Thread(){
#Override
public void run(){
try {
sleep(2000);
} catch (InterruptedException e) {}
test=false;
}
};
user.start();
while(test) {
System.out.println("foo"); //Without this line the program does not terminate..
}
}
}
The most likely explanation is that the variable is only read once, turning the while into an infinite loop (or a no-op). Since you haven't declared test as volatile, the compiler is allowed to perform such an optimization.
Once you call an external function from within the loop, the compiler can no longer prove that test remains invariant across loop iterations, and doesn't perform the optimization.
If the test variable is not defined as volatile, the compiler probably optimizes the loop containing no operation into a while(true) loop for your main thread and the program never ends.
Otherwise, the value of the test variable is actually checked and when your second thread changes its value, then the main thread leaves the while loop and your program terminates.
I presume it's something to do with the way IO is handled. Without the print, you'll probably see the java application using all available CPU time; with the print it's likely that IO delays give up enough CPU time for other processing to take place.
A quick way to test this theory would be to put printlns in the run() method of your thread to see whether the thread is actually ever executing. In my experience, infinite empty loops cause a lot of strange behaviour.
That said, it appears to terminate fine on my workstation under JDK 1.6.0_10_b23
Seems like your loop is being incorrectly compiled away into a busy-wait. Adding a volatile keyword to your boolean corrects the 'problem'.
public static boolean test = true;
public static void main(String[] args) {
Thread user =new Thread(){
#Override
public void run(){
try {
sleep(2000);
} catch (InterruptedException e) {}
test=false;
System.out.println("Thread.end <"+test+">");
}
};
user.start();
while(test);
}
That's interesting. The compiler most probably optimzes this while into an endless loop, not reading the value at each loop.
Defining test as volatile fixes this and let your program terminate
Btw: you probably already know that you shoud use user.join() to wait for the Thread to end
I don't understand what you are trying to do by using code you know is not correctly synchronized.
As some have reported, on their machine the code behaves differently than on your machine. The behavior of badly synchronized code is undefined. It makes no sense to try to understand what it does since that behavior will change with the JVM version or architecture.