This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 5 years ago.
I was confused with a code snippet like this:
public class LearnTest {
private static boolean tag = true;
private static int i = 0;
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
while (tag) {
//System.out.println("ok");
i++;
}
}
}).start();
try {
Thread.sleep(1000);
}catch (Exception e) {
e.printStackTrace();
}
tag = false;
System.out.println(i);
}
}
In the code, we have a new-thread and main-thread.The result about this code will be a random value of i and the new-thread will not exit.Because new-thread will not get the new tag value.
if we change the define of tag which will be decorated with volatile, it will print some value of i and new-thread will exit. Because volatile will keep the visibility for all thread.
But when I cannel the comment for the commentted code line,and thetag will not be decorated witch volatile,it will print some "ok" and exit.
why?
what I suppose is that Java's IO will do something like synchronized, it will force the tag side value of new-thread to refresh from main shared memory.
This's corret?
Without volatile the thread is not guaranteed to see changes to the value. It may see them.
In this case adding the System.out.println() results (apparently) in the value being removed from the cache, so it's fetched from the main memory at some point. Without the println() the value remains in cache, and you get the infinite (or at least very long) loop.
That's one difficulty with concurrent programming, sometimes code may appear to work correctly, but there's no way to be certain it always works correctly.
Related
I understood that reading and writing data from multiple threads need to have a good locking mechanism to avoid data race. However, one situation is: If multiple threads try to write to a single variable with a single value, can this be a problem.
For example, here my sample code:
public class Main {
public static void main(String[] args) {
final int[] a = {1};
while(true) {
new Thread(new Runnable() {
#Override
public void run() {
a[0] = 1;
assert a[0] == 1;
}
}).start();
}
}
}
I have run this program for a long time, and look like everything is fine. If this code can cause the problem, how can I reproduce that?
Your test case does not cover the actual problem. You test the variable's value in the same thread - but that thread already copied the initial state of the variable and when it changes within the thread, the changes are visible to that thread, just like in any single-threaded applications. The real issue with write operations is how and when is the updated value used in the other threads.
For example, if you were to write a counter, where each thread increments the value of the number, you would run into issues. An other problem is that your test operation take way less time than creating a thread, therefore the execution is pretty much linear. If you had longer code in the threads, it would be possible for multiple threads to access the variable at the same time. I wrote this test using Thread.sleep(), which is known to be unreliable (which is what we need):
int[] a = new int[]{0};
for(int i = 0; i < 100; i++) {
final int k = i;
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(20);
} catch(InterruptedException e) {
e.printStackTrace();
}
a[0]++;
System.out.println(a[0]);
}
}).start();
}
If you execute this code, you will see how unreliable the output is. The order of the numbers change (they are not in ascending order), there are duplicates and missing numbers as well. This is because the variable is copied to the CPU memory multiple times (once for each thread), and is pasted back to the shared ram after the operation is complete. (This does not happen right after it is completed to save time in case it is needed later).
There also might be some other mechanics in the JVM that copy the values within the RAM for threads, but I'm unaware of them.
The thing is, even locking doesn't prevent these issues. It prevents threads from accessing the variable at the same time, but it generally doesn't make sure that the value of the variable is updated before the next thread accesses it.
This question already has answers here:
Why doesnt this Java loop in a thread work?
(4 answers)
Closed 3 years ago.
For a recent library I'm writing, I wrote a thread which loops indefinitely. In this loop, I start with a conditional statement checking a property on the threaded object. However it seems that whatever initial value the property has, will be what it returns even after being updated.
Unless I do some kind of interruption such as Thread.sleep or a print statement.
I'm not really sure how to ask the question unfortunately. Otherwise I would be looking in the Java documentation. I have boiled down the code to a minimal example that explains the problem in simple terms.
public class App {
public static void main(String[] args) {
App app = new App();
}
class Test implements Runnable {
public boolean flag = false;
public void run() {
while(true) {
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {}
if (this.flag) {
System.out.println("True");
}
}
}
}
public App() {
Test t = new Test();
Thread thread = new Thread(t);
System.out.println("Starting thread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
t.flag = true;
System.out.println("New flag value: " + t.flag);
}
}
Now, I would presume that after we change the value of the flag property on the running thread, we would immediately see the masses of 'True' spitting out to the terminal. However, we don't..
If I un-comment the Thread.sleep lines inside the thread loop, the program works as expected and we see the many lines of 'True' being printed after we change the value in the App object. As an addition, any print method in place of the Thread.sleep also works, but some simple assignment code does not. I assume this is because it is pulled out as un-used code at compile time.
So, my question is really: Why do I have to use some kind of interruption to get the thread to check conditions correctly?
So, my question is really: Why do I have to use some kind of interruption to get the thread to check conditions correctly?
Well you don't have to. There are at least two ways to implement this particular example without using "interruption".
If you declare flag to be volatile, then it will work.
It will also work if you declare flag to be private, write synchronized getter and setter methods, and use those for all accesses.
public class App {
public static void main(String[] args) {
App app = new App();
}
class Test implements Runnable {
private boolean flag = false;
public synchronized boolean getFlag() {
return this.flag;
}
public synchronized void setFlag(boolean flag) {
return this.flag = flag;
}
public void run() {
while(true) {
if (this.getFlag()) { // Must use the getter here too!
System.out.println("True");
}
}
}
}
public App() {
Test t = new Test();
Thread thread = new Thread(t);
System.out.println("Starting thread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
t.setFlag(true);
System.out.println("New flag value: " + t.getFlag());
}
But why do you need to do this?
Because unless you use either a volatile or synchronized (and you use synchronized correctly) then one thread is not guaranteed to see memory changes made by another thread.
In your example, the child thread does not see the up-to-date value of flag. (It is not that the conditions themselves are incorrect or "don't work". They are actually getting stale inputs. This is "garbage in, garbage out".)
The Java Language Specification sets out precisely the conditions under which one thread is guaranteed to see (previous) writes made by another thread. This part of the spec is called the Java Memory Model, and it is in JLS 17.4. There is a more easy to understand explanation in Java Concurrency in Practice by Brian Goetz et al.
Note that the unexpected behavior could be due to the JIT deciding to keep the flag in a register. It could also be that the JIT compiler has decided it does not need force memory cache write-through, etcetera. (The JIT compiler doesn't want to force write-through on every memory write to every field. That would be a major performance hit on multi-core systems ... which most modern machines are.)
The Java interruption mechanism is yet another way to deal with this. You don't need any synchronization because the method calls that. In addition, interruption will work when the thread you are trying to interrupt is currently waiting or blocked on an interruptible operation; e.g. in an Object::wait call.
Because the variable is not modified in that thread, the JVM is free to effectively optimize the check away. To force an actual check, use the volatile keyword:
public volatile boolean flag = false;
This question already has answers here:
Mutithreading with System.out.format and System.out.println
(4 answers)
Closed 5 years ago.
I am trying to understand how to create a deadlock from https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html.
Instead of copy and pasting the sample code, I chose to write it by myself.
The last line in the link says "neither block will ever end because each thread is waiting for the other to exit bow" but never mentions about System.out.format.
I then wrote the below code and it never entered deadlock
public class DeadlockTest {
static class Resource {
public synchronized void test1(Resource r) {
System.out.print("test1");
r.test2();
}
public synchronized void test2() {
System.out.print("test2");
}
}
public static void main(String... a) {
final Resource r1 = new Resource();
final Resource r2 = new Resource();
new Thread(new Runnable() {
public void run() {
r1.test1(r2);
}
}).start();
new Thread(new Runnable() {
public void run() {
r2.test1(r1);
}
}).start();
}
}
So I tried to compare line by line and found that only the print statement is wrong. Instead of using System.out.format I used System.out.print. So the code never ran in to a dead lock situation. I then changed it to System.out.format and I was able to simulate a dead lock.
I even copied the example code from the link, changed the format statement to print/println and it was not entering deadlock.
Can anyone please explain how to exactly create a deadlock?
I took your code to test it. It indeed ran fine.
Only when I added a Thread.sleep(100) or the String.format in test1, it blocked. It seems as if your "work" method (print) is too fast. Before the second thread can cause the block by calling test1, the first thread is already finished with test2.
To stay in the tutorials example: Your threads did not in fact "bow at each other at the same time", but only "very quickly after one another". Make the bowing a little slower and you increase the chances of them bowing at the same time (still not guaranteed, e.g. if the system takes longer to schedule the second thread).
This question already has answers here:
Relationship between Threads and println() statements
(2 answers)
Closed 6 years ago.
I was going through the use cases for volatile and I have encountered the below scenario:
private static boolean stop = false;
public static void main(String[] args) throws InterruptedException {
Thread runner = new Thread(new Runnable() {
#Override
public void run() {
int i = 0;
long start = System.currentTimeMillis();
while(!stop){
i++;
}
System.out.println("I m done after "+(System.currentTimeMillis() - start));
}
});
runner.start();
Thread.sleep(2000);
stop = true;
}
The above code runs indefinitely. Which is fine due to hoisting done by the compiler in an attempt to optimize the code. However, if I replace, i++ with some other statement e.g. System.out.println("Hello"). It stops after 2 seconds.
Why the behavior is like this? I am using jdk1.7.0_51.
Note:
I know I should declare stop as volatile. However, I would like to know the reason for the behavior in the above case.
The standard output is a shared resource across threads. Java's PrintStream class is made thread-safe using synchronized blocks, and all synchronized blocks are memory barriers in java, that's why changes on the stop field become visible inside the loop. However, you shouldn't rely on this.
For example, take a look at the PrintStream.println implementation:
public void println(String paramString)
{
synchronized (this)
{
print(paramString);
newLine();
}
}
This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
I've noticed this bug (if it is a bug) and decided to make a test environment. Does anyone know if this is an actual problem or is it just me?
import java.util.Random;
public class Start {
public static boolean value;
public static void main(String[] args){
Thread thread = new Thread(){
#Override
public void run(){
random();
}
};
thread.start();
while(true){
if(value) System.out.println("Done");
}
}
public static void random(){
while(true){
value = new Random().nextInt(5) == 0;
}
}
}
I would expect this code to be spamming out "Done"s, but instead I get a bunch at the beginning and then no additions. When I modify the code as so:
while(true){
System.out.print(""); //Modification
if(value) System.out.println("Done");
}
It starts spamming the "Done"s. Anyone know what's up?
NOTE: I have tested this in an Eclipse environment and a compiled jar while using jdk 1.8.0 v.25 and jre 1.8.0 v.51.
I suspect that you hit a compiler optimization called hoisting - it recognizes that you overwrite value without having these changes "visible" to other threads and that's why it optimizes at some point and stops printing.
This behavior will change to what is likely the "wanted" behavior once you'll declare value as volatile - then updates to it become visible to other threads and then the printings will keep on forever.