As typed below, the program has a shared var flag without volatile:
public class T {
public static void main(String[] args) {
TT jump = new TT(() -> {
while (true) {
if (TT.flag) {
System.out.println("jump");
break;
}
}
});
jump.start();
new TT(() -> {
TT.flag = true; // P1
LocalDateTime t1 = LocalDateTime.now();
while (true) {
if (Duration.between(t1, LocalDateTime.now()).toMillis() > 100) {
break;
}
}
System.out.println("flag");
}).start();
}
static class TT extends Thread {
public static boolean flag = false;
public TT(Runnable o) {
super(o);
}
}
}
The program always returns normally. So I believe the line of P1 ,where the flag was set to true, updated flag in other threads.
But why? flag is not volatile, why its value was updated immediately? Always!
But why? flag is not volatile, why its value was updated immediately? Always!
You are simply lucky; or unlucky, depending upon your perspective. I tried this on Ideone, and found that it timed out rather than terminating normally.
Remember: not being able to observe a concurrency bug is not the same as an absence of a concurrency bug.
The most sure you can be about code is when you can prove, according to the specification, that there are no bugs. That doesn't mean that the code will then work correctly; it just means that the problems are in the JVM implementation.
In particulary, you can't prove that this code will work correctly, because there is no happens-before relationship between the write to flag in the second thread, and the read in the first thread. Adding volatile creates this guarantee, because a volatile write happens before a volatile read.
That's not to say it will never work without volatile, it's just not guaranteed: a JVM only has to flush a thread's cached values at least as often as the spec requires, but can do it more often, or indeed not cache values at all.
Related
Sample code:
public class TestTestTest {
private void setFalseFlag() {
this.keepRunning = false;
System.out.println("keepRunning is false");
}
private boolean keepRunning = true;
public static void main(String[] args) throws InterruptedException {
TestTestTest t = new TestTestTest();
Thread startLoop = new Thread(() -> {
System.out.println("before loop");
while (t.keepRunning) {}
});
Thread flagChanger = new Thread(() -> {
System.out.println("before setting flag");
t.setFalseFlag();
});
startLoop.start();
Thread.sleep(1000);
flagChanger.start();
}
}
This code sample starts and never finishes, because keepRunning changes are not visible to the other thread. Of course, if I use volatile or AtomicBolean for keepRunning programm starts and stops properly.
But, as far as I know synchronized block or locks provides flushes to main memory on entering and on exiting or smth like that, info taken from documentation. But I can't understand how to implement it on this code sample. Looks like it is not even possible to sync on one monitor here.
Oracle Documentation
All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock:
A successful lock operation acts like a successful monitorEnter action
A successful unlock operation acts like a successful monitorExit action
JSR-133 FAQ
But there is more to synchronization than mutual exclusion. 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. After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory. We will then be able to see all of the writes made visible by the previous release.
So here is the question, am I right that it is not possible here? Or if not, how to do it properly?
"synchronized block or locks provides flushes to main memory on entering and on exiting"
You can't because you're accessing keepRunning directly. That's why volatile works, because you can put it directly on the field. If you want to use synchronized, you need a section of code that only accesses keepRunning while a lock is held (in computer science this section of code is called a "critical section").
// CHANGE
private synchronized void setFalseFlag() {
// CHANGE
run = false;
System.out.println("keepRunning is false");
}
// CHANGE
private synchronized boolean keeRunning() {
// CHANGE
return run;
}
// CHANGE
private boolean run = true;
public static void main(String[] args) throws InterruptedException {
TestTestTest t = new TestTestTest();
Thread startLoop = new Thread(() -> {
System.out.println("before loop");
// CHANGE
while (t.keepRunning()) {}
});
You can do:
private Boolean keepRunning = true; //change to object so it can be synchronized one
...
while (true)
{
synchronized (t.keepRunning)
{
if (!t.keepRunning)
{
break;
}
}
}
But better do volatile thingy.
I think the reason your version doesn't break is that java isn't guaranteed to watch variables changed from other threads unless it's volatile, therefor the while loop check is optimized to true.
I am using jdk1.8.
This code runs directly into an infinite loop, but if I add the commented code, it will run normally. I have tried a lot of codes, as long as the operation of locking is involved, it can run normally.
public class StateTest {
public static void main(String[] args) {
State state = new State();
new Thread(new Work(state)).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
state.setStart(true);
System.out.println("the main thread is finished");
}
static class State {
private boolean isStart = false;
public boolean isStart() {
return this.isStart;
}
public void setStart(boolean start) {
this.isStart = start;
}
}
static class Work implements Runnable {
private State state;
public Work(State state) {
this.state = state;
}
#Override
public void run() {
int i = 0;
//endless loop
while (!this.state.isStart()) {
i++;
// if open this code,it will be ok
// synchronized (this) {
//
// }
}
System.out.println(String.format("work start run after %s loops", i));
}
}
}
The problem is that a State instance is not thread-safe. If one thread calls setStart and a second thread calls isStart, then the second thread may not see the value that the first one set1.
You are using setStart on a State instance so that one instance can signal a second one to end the loop. If the second thread doesn't see the state change (because of the above) then the loop won't terminate2.
Solutions:
Change setStart and isStart to be synchronized methods.
Declare the isStart field to be volatile.
Instead of writing your own State class, use a standard java.util.concurrent class to do the synchronization; e.g. CountDownLatch (javadoc).
I recommend that you take the time to study the Oracle Java Tutorial Lesson on concurrency:
The Java™ Tutorials: Lesson: Concurrency
1 - The technical explanation for why this can happen is set out in the "Java Memory Model" section of the Java Language Specification. However, the JLS is NOT written in a way that beginners can understand, and that part is particularly difficult.
2 - In fact, the JLS doesn't say whether the change will be seen or not seen. The actual behavior is liable to depend on a range of factors that are outside of the programmer's control.
It is not guaranteed the isStart value update is visible in the newly created thread.
Since multiple threads access the isStart field, you want to mark it as volatile to assure the updated variable value will be written always in the main memory and not the CPU cache.
static class State {
private volatile boolean isEnd = false;
// getters & setters
}
To my understanding the following code should terminate normally as the condition stopRunning = true; is met.
However, when I run this program it is printing only Last line of Main(), Start Method ended is never printed as the while loop is never terminated.
public class Test {
private static boolean stopRunning = false;
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
#Override
public void run() {
start();
}
}).start();
Thread.sleep(100);
stopRunning = true;
System.out.println("Last line of Main()");
}
public static void start() {
while (!stopRunning) {
}
System.out.println("Start Method ended.");
}
}
Please help me understand this behavior.
Changing the flag to volatile with
private static volatile boolean stopRunning = false;
will mean that other threads see the change immediately (from main memory instead of a cache), and the code executes as you expect. How volatile relates to Java's memory model is explained further e.g. in this tutorial.
As Mick stated, you should use the volatile keyword to synchronize your variable, so on a change the new value is written directly back to memory and your code will work as expected.
Be aware (also stated in the article Mick linked) that volatile does not guarantee to avoid race conditions, so if two different threads would read your variable, it is not safe that they both read the same value (despite everything is read from memory and on change directly written back)
As stated in previous answers:
Like Mike stated - in run() you should use Test.start() or rename the method. The start you are calling is the thread's start method.
Also as Mick stated, setting stopRunning as volatile should help. The reason it should work is that it will remove the caching of the variable in the thread's memory and will get/set directly from memory.
I have the following code:
public static boolean turn = true;
public static void main(String[] args) {
Runnable r1 = new Runnable() {
public void run() {
while (true) {
while (turn) {
System.out.print("a");
turn = false;
}
}
}
};
Runnable r2 = new Runnable() {
public void run() {
while (true) {
while (!turn) {
System.out.print("b");
turn = true;
}
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
In class we've learned about "Visibility" problems that may occur when using un-synchronized code.
I understand that in order to save time, the compiler will decide the grab turn to the cache in the CPU for the loop, meaning that the thread will not be aware if the turn value was changed in the RAM because he doesn't check it.
From what I understand, I would expected the code to run like this:
T1 will see turn as true -> enter loop and print -> change turn to false -> gets stuck
T2 will think turn hasn't changed -> will get stuck
I would expect that if T1 will start before T2: only 'a' will be printed and both threads will run in an infinite loop without printing anything else
However, when I'm running the code sometimes I get a few "ababa...." before both threads will stuck.
What am I missing ?
EDIT:
The following code does what I expect it: the thread will run in a infinite loop:
public class Test extends Thread {
boolean keepRunning = true;
public void run() {
long count = 0;
while (keepRunning) {
count++;
}
System.out.println("Thread terminated." + count);
}
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
t.start();
Thread.sleep(1000);
t.keepRunning = false;
System.out.println("keepRunning set to false.");
}
}
How are they different from each other ?
When I run the code, sometimes I get a few "ababa...." before both threads will stuck.
I suspect that what is happening is that the behavior is changing when the code is JIT compiled. Before JIT compilation the writes are visible because the interpreter is doing write-throughs. After JIT compilation, either the cache flushes or the reads have been optimized away ... because the memory model allows this.
What am I missing ?
What you are missing is that you are expecting unspecified behavior to be consistent. It doesn't have to be. After all, it is unspecified! (This is true, even if my proposed explanation above is incorrect.)
The fact that turn isn't volatile doesn't mean that your code WILL break, just that it MIGHT break. For all we know, the thread could see false or true at any given moment. Caches could just be randomly flushed for no reason in particular, the thread could retain its cache, etc etc.
It could be because your code is experiencing side effects from System.out.print, which internally writes to a synchronized method:
521 private void write(String s) {
522 try {
523 synchronized (this) {
(Source - DocJar)
The memory effects of synchronized could be flushing the cache and therefore impact your code.
As #Stephen C said, it could also be the JIT, which might hoist the boolean check because it assumes that the value can't change due to another thread.
So out of the three different possibilities mentioned so far, they could all be factors to contribute to how your code behaves. Visibility is a factor, not a determiner.
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;
}
}
According to "Java Concurrency in Practice", it may be possible that it will print 0 as write to ready might be made visible to the reader thread before write to a number or program never terminate at all because it does not use adequate synchronization. It is not guaranteed that values of ready and number written by main thread will be visible to reader thread.
How is it possible? Program will be run sequentially by a thread and it first writes to number and then ready variable. Isn't it? And how can this program could loop forever?
There are no guarantees that by changing a variable in one thread, other threads will see the results of those changes. Technically there is no happens-before relation between them and thus no guarantees (whilst in practice you'll see the changes almost all the time).
That's why the thread may run forever.
Secondly, why sometimes 0 ?
Well the JLS says that
Writes in one thread that are in a data race with reads in another
thread may, for example, appear to occur out of order to those reads.
Which means that your
number = 42;
ready = true;
Can occur in any order. Now it's more likely they'll appear in order, but again there's no guarantees.
You could fix it by changing the variables to be volatile, in which case the writes will always be visible to the readers or by making the code where you mutate state a critical section (see the book). In general I feel using too many volatile variables is a bit of a hack, so you should try and use them sparingly, for things like thread "running" variables.
public class NoVisibility {
private static volatile boolean ready;
private static volatile 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;
}
}
If ready is not marked as 'volatile' than the ReaderThread might check its value (as 0).
It later does not check again about ready's value because it assume it has not changed.
The volatile keyword instructs the compiler not to have such assumptions at all and that the variable's value might change under his feet.