Thread.sleep behaviour with non-volatile boolean variable - java

According to the JLS 17 specification section 17.3:
For example, in the following (broken) code fragment, assume that this.done is a non-volatile boolean field:
while (!this.done)
Thread.sleep(1000);
The compiler is free to read the field this.done just once, and reuse the cached value in each execution of the loop. This would mean that the loop would never terminate, even if another thread changed the value of this.done
I have tried to simulate this following example: 2 threads concurrently access the same boolean variable, the first thread using the shared boolean in while loop, and the second thread update the boolean value.
1.Code without Thread.sleep() inside the first thread:
public boolean done;
public void performTest() throws InterruptedException {
done = false;
new Thread(() -> {
System.out.println("Running Thread 1...");
int count = 0;
while (!done) {
count++;
}
System.out.println("Exiting thread...");
}).start();
Thread.sleep(100);
new Thread(() -> {
System.out.println("Thread 2 setting done to true");
done = true;
}).start();
}
-> This code would never terminated, because the done variable not declared as volatile
2.Now change the code to include Thread.sleep() inside while loop as mentioned in the JLS
public boolean done;
public void performTest() throws InterruptedException {
done = false;
new Thread(() -> {
System.out.println("Running Thread 1...");
int count = 0;
while (!done) {
count++;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Exiting thread...");
}).start();
Thread.sleep(100);
new Thread(() -> {
System.out.println("Thread 2 setting done to true");
done = true;
}).start();
}
-> Now it successfully exists in the first thread.
So i am confused between this example and the JLS mentioned. Not sure what i am missing here.
Note: i also noticed that Venkat's also mentioned this example in one of his videos, and there is a blog post that explained this behavior, and it looks like there is something related to JIT optimization. What is really concerned me here is that this example is not like what is described in the JLS.

The reason that the code is broken in your example is because the JVM is free to use a cached version of done so that your loop would never end. When you have 'Thread.sleep()' in there, it is unlikely to happen, but it is still a possiblity. That means, you write some code and test it and it works great. Then you change an environment, or change a JVM and suddenly it is broken.
This is a poor benchmark, but it gives an idea.
public class VolatileTest implements Runnable{
boolean done = false;
public void run(){
long count = 0;
long start = System.nanoTime();
long end = Integer.MAX_VALUE;
while(!done){
count++;
if(count == end){
break;
}
//try{ Thread.sleep(0); } catch (Exception e){ break;}
}
System.out.println( System.nanoTime() - start + " with " + count + " iterations");
}
public static void main(String[] args) throws Exception{
VolatileTest vt = new VolatileTest();
new Thread(vt).start();
Thread.sleep(500);
vt.done = true;
}
}
Now there are 3 cases. 1st as written without any sleep/volatile.
650503733 with 2147483647 iterations
It took 650ms to complete Integer.MAX_VALUE iterations. note sometimes this
finishes faster than the 500ms I wait.
2nd case, volatile done.
499923823 with 1091070867 iterations
Now it never completes before vt.done is set to true.
3rd case. non-volatile with Thread.sleep
499905166 with 3031374 iterations
With the volatile version is 300 times faster than the Thread.sleep version. The non-volatile version is more intermittent in how fast it is but it is the fastest. I suspect due to when the JIT decides to cache done it gets a speed boost so to speak.
I'm not sure how to verify when it decides to cache the done variable, but I think that why JMH is necessary for these types of micro benchmarks.

Related

java multithread performance on sync object

I am trying to test the multithreading performance with sync'ed object. However,
with 1 thread or with 16 threads the execution time is the same.
The rest of the code is here.
https://codeshare.io/5oJ6Ng
public void run() {
start = new Date().getTime();
System.out.println(start);
while (threadlist.size() < 9000) { //16 or more
// try{Thread.sleep(100);}catch (Exception f){}
Thread t = new Thread(new Runnable() {
public void run() {
while (add(1,3) < 1000000);
end = new Date().getTime();
System.out.println((end-start));
}
});
threadlist.add(t);
while( threadlist.iterator().hasNext()){
threadlist.iterator().next().start();
try{threadlist.iterator().next().join();}catch (Exception a){}
}
}
}
There are some issues with your code. First:
public void run() {
while (true) {
add(1, 3);
}
}
Those threads never stop working, I would suggest rewriting your logic to:
public void (run) {
while(add(1,3) < 1000000);
System.out.println("now 1000000");
}
public int add(int val1, int val2) {
synchronized (this) {
this.sum1 += val1;
this.sum2 += val2;
return this.sum1 + this.sum2;
}
}
}
You start the threads, but you never call join, eventually you will need to do that.
You are only creating 1 thread instead of the 16 that you wanted:
if (threadlist.size() < 1)
you want
if (threadlist.size() < 16)
Finally, do not expect any performance gain with this code, since you are synchronizing on the object:
synchronized (this){...}
So basically your add method is being run sequentially and not in parallel, since threads will wait on synchronized (this) and call only run on at the time inside your the block of code wrapped by the synchronized statement.
Try to measure your time by adding start = new Date().getTime(); before the parallel region, and end = new Date().getTime(); after.
You can simply your code to:
public void run() {
start = new Date().getTime();
System.out.println(start);
while (threadlist.size() < 16) {
Thread t = new Thread(() -> {
while (add(1,3) < 1);
System.out.println("now 1000000");
});
threadlist.add(t);
}
threadlist.forEach(Thread::start);
threadlist.forEach(thr-> {
try { thr.join();}
catch (InterruptedException e) { e.printStackTrace();}
});
end = new Date().getTime();
System.out.println("Time taken : "+(end-start));
public int add(int val1, int val2) {
synchronized (this) {
this.sum1 += val1;
this.sum2 += val2;
return this.sum1 + this.sum2;
}
}
}
You've significantly updated your code since #dreamcrash answered.
The current version has the following issues:
while( threadlist.iterator().hasNext()) {
threadlist.iterator().next().start();
try{threadlist.iterator().next().join();}catch (Exception a){}
}
This starts a thread and then will immediately sit around, twiddling its thumbs until that thread is completely done with its job, and will then fire up another thread. Therefore, you never more than 1 active thread at a time.
catch (Exception a){}
You're learning / debugging, and you do this? Oh dear. Don't. Don't ever write a catch block like that. Update your IDE or your muscle memory: The right "I dont want to think about exceptions right now" code is catch (Exception a) { throw new RuntimeException("Unhandled", a);}. To be clear, this isn't the problem, but this is such a bad habit, it needed to be called out.
synchronized (this) {
I really doubt if you fix the 'join' issue I mentioned earlier this will ever run any faster. This synchronized call is important, but it also causes so much blockage that you're likely to see zero actual benefit here.
More generally the calculation you are trying to speed up involves an accumulator.
accumulator is another word for 'parallelising is utterly impossible here, it is hopeless'.
The algorithm cannot involve accumulators if you want to parallellize it, which is what multithreading (at least, if the aim of the multiple threads is to speed things up) is doing. This algorithm cannot be made any faster with threads. period.
Usually algorithms can be rewritten to stop relying on accumulators. But this is clearly an exercise to see an effect, so, just find anything else, really. Don't lock on a single object for the entire calculation: Only one thread is ever actually doing work, all the 999 others are just waiting.

Unexpected thread behavior. Visibility

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.

Thread Signalling Sequence

In the below code I have implemented inter Thread communication using wait() -notify() and it is giving me expected output.
expected Output : 123456789 Actual output : 123456789
My question is , is there any guarantee that always 'Main Thread' will get the first chance to execute, since Thread scheduling depends on jvm. And if 'child thread' gets the first chance, the notify() signal will miss and the 'main Thread ' will wait forever. How can I confirm that 'Main thread' will execute first always. Also please confirm if the below code can be improved.
package com.test.Thread;
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException{
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj .start();
synchronized(lockingObj ){
for(int i=1;i<10;i++){
System.out.println("Main "+i);
}
lockingObj.wait();
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
public void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println("Child "+i);
}
this.notify();
}
}
}
Your code is wrong for the reason that you mentioned yourself: you can't be sure which thread goes first.
There are other things that could go wrong - wait can wake up without a notify.
You can read about it in the Javadoc for the wait method, which also explains what you should do:
As in the one argument version, interrupts and spurious wakeups are
possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
In your code, you can solve it with a boolean variable that expresses the condition "I was notified":
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException {
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj.start();
synchronized (lockingObj) {
for(int i = 1; i < 10; i++) {
System.out.println("Main " + i);
}
while (!lockingObj.haveNotified) {
lockingObj.wait();
}
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
private boolean haveNotified;
public void run(){
synchronized (this) {
for (int i = 1; i < 10; i++) {
System.out.println("Child " + i);
}
haveNotified = true;
this.notify();
}
}
}
While this works correctly on your system, it is not a guranty as your suspicion might become true on a different system. Threading behavior is verry difficult/impossible to predict. Therefore I like to think in worst case scenarios, and if I can come up with a possible breaking situation (as you just described one) I simply redesign to make sure it will work.
A nice trick to test your code is to suspend/pause threads on critical moments by either adding a breakpoint in your IDE, adding a verry time consuming task/call if possible (not failsafe), or by fysically pausing the thread(not always ideal). Besides Im sure there is are libraries to expand on this type of tesing.
I hope this helps you a bit in the right direction.

Are unsynchronized reads (combined with synchronized writes) eventually consistent

I have a use case with many writer threads and a single reader thread. The data being written is an event counter which is being read by a display thread.
The counter only ever increases and the display is intended for humans, so the exact point-in-time value is not critical. For this purpose, I would consider a solution to be correct as long as:
The value seen by the reader thread never decreases.
Reads are eventually consistent. After a certain amount of time without any writes, all reads will return the exact value.
Assuming writers are properly synchronized with each other, is it necessary to synchronize the reader thread with the writers in order to guarantee correctness, as defined above?
A simplified example. Would this be correct, as defined above?
public class Eventual {
private static class Counter {
private int count = 0;
private Lock writeLock = new ReentrantLock();
// Unsynchronized reads
public int getCount() {
return count;
}
// Synchronized writes
public void increment() {
writeLock.lock();
try {
count++;
} finally {
writeLock.unlock();
}
}
}
public static void main(String[] args) {
List<Thread> contentiousThreads = new ArrayList<>();
final Counter sharedCounter = new Counter();
// 5 synchronized writer threads
for(int i = 0; i < 5; ++i) {
contentiousThreads.add(new Thread(new Runnable(){
#Override
public void run() {
for(int i = 0; i < 20_000; ++i) {
sharedCounter.increment();
safeSleep(1);
}
}
}));
}
// 1 unsynchronized reader thread
contentiousThreads.add(new Thread(new Runnable(){
#Override
public void run() {
for(int i = 0; i < 30; ++i) {
// This value should:
// +Never decrease
// +Reach 100,000 if we are eventually consistent.
System.out.println("Count: " + sharedCounter.getCount());
safeSleep(1000);
}
}
}));
contentiousThreads.stream().forEach(t -> t.start());
// Just cleaning up...
// For the question, assume readers/writers run indefinitely
try {
for(Thread t : contentiousThreads) {
t.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void safeSleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
//Don't care about error handling for now.
}
}
}
There is no guarantee that the readers would ever see an update to the count. A simple fix is to make count volatile.
As noted in another answer, in your current example, the "Final Count" will be correct because the main thread is joining the writer threads (thus establishing a happens-before relationship). however, your reader thread is never guaranteed to see any update to the count.
JTahlborn is correct, +1 from me. I was rushing and misread the question, I was assuming wrongly that the reader thread was the main thread.
The main thread can display the final count correctly due to the happens-before relationship:
All actions in a thread happen-before any other thread successfully returns from a join on that thread.
Once the main thread has joined to all the writers then the counter's updated value is visible. However, there is no happens-before relationship forcing the reader's view to get updated, you are at the mercy of the JVM implementation. There is no promise in the JLS about values getting visible if enough time passes, it is left open to the implementation. The counter value could get cached and the reader could possibly not see any updates whatsoever.
Testing this on one platform gives no assurance of what other platforms will do, so don't think this is OK just because the test passes on your PC. How many of us develop on the same platform we deploy to?
Using volatile on the counter or using AtomicInteger would be good fixes. Using AtomicInteger would allow removing the locks from the writer thread. Using volatile without locking would be OK only in a case where there is just one writer, when two or more writers are present then ++ or += not being threadsafe will be an issue. Using an Atomic class is a better choice.
(Btw eating the InterruptedException isn't "safe", it just makes the thread unresponsive to interruption, which happens when your program asks the thread to finish early.)

incrementing a static variable thru' 100 different threads without synchronisation, yet getting the final result as 100

I'm incrementing a static variable thru' 100 different threads without synchronisation, yet getting the final result as 100. I've run this code several times and have got same result. Does my code then not require synchronisation? I'm using BlueJ IDE to run the code
public class Main {
private final static int MAX_THREADS = 100;
public static void main(String[] args) {
Thread[] threads = new Thread[MAX_THREADS];
for(int i=0; i<MAX_THREADS; i++) {
threads[i] = new Thread(new Job(), "Thread-" + i);
threads[i].start();
try{
Thread.sleep((int)(Math.random() * 1000));
}catch(InterruptedException e) {
e.printStackTrace();
}
}
for(int i=0; i<MAX_THREADS; i++) {
try {
threads[i].join();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf("Final Value: %d\n", Job.getSuccessCount());
}
}
public class Job implements Runnable {
private static int successCount;
public static int getSuccessCount() {return successCount;}
#Override
public void run() {
System.out.printf("%s: Incrementing successCount %d\n", Thread.currentThread().getName(), successCount);
try{
Thread.sleep((int)(Math.random() * 10000));
}catch(InterruptedException e) {
e.printStackTrace();
}
successCount++;
System.out.printf("%s: Incrementing Complete %d\n", Thread.currentThread().getName(), successCount);
}
}
Basically in you code, due to the sleep statements (both in the Thread and by the launcher), you are effectively kicking off the threads allowing for plenty of non busy time to update. That is why it is working. If you code was really multi-threaded, the you would face synchronization issues.
Adding to Wombat's Answer. The final result will always be 100 because you do a Unary Operation after The Sleep in Job class. Basically the read-modify-write commands can run sequentially per Job if the Java Scheduler didn't change the status of the Thread while performing the following.
successCount++
But if you change the Job source code to read-sleep-modify-write then you will definitely see stale value as following.
public class Job implements Runnable {
private static int successCount;
public static int getSuccessCount() {return successCount;}
#Override
public void run() {
System.out.printf("%s: Incrementing successCount %d\n", Thread.currentThread().getName(), successCount);
int sc = successCount; // Read
try{
Thread.sleep((int)(Math.random() * 10000)); // Sleep
}catch(InterruptedException e) {
e.printStackTrace();
}
successCount = sc++; // Modify-Write
System.out.printf("%s: Incrementing Complete %d\n", Thread.currentThread().getName(), successCount);
}
}
With this 2 Threads can read and then sleep and then wake up and write the same value to successCount overwriting the original value.
Your code currently doesn't need synchronization, as no two treads access the same variable at the same time. In other words, only 1 thread in your application is incrementing the variable.
In this case, it is due to the fact that incrementing the variable takes less than Math.random() *1000. Why is it so? Let's observe the threads:
Main Thread:
Launches and starts a thread
Executes both Math.random() and Thread.sleep()
Loops again
While the main thread is doing step 2, the new thread is:
Incrementing variable
Going to sleep
In this case, once the new thread goes to sleep, it just is killed right after, therefore, for our purpose we can regard it as if the thread terminates right after step 1, as it stops affecting the variable (it has no influence on the variable after step 1).
In order for a synchronization problem to occur, two new threads need to access the variable at once. For this to happen, main thread must launch a new thread before the first new thread finishes incrementing. For that to happen, main thread must be faster in: executing Math.random(), Thread.sleep(), and creating a new thread, all before the other thread finishes incrementing. This is obviously not the case, and thus no 2 threads will increment at once, and no synchronization error will occur.
If you do the sums you'll see that you have an average of ten threads running at the same time, all sleeping for an average of five seconds and then doing an increment. So on average the increments won't be closer together than half a second, and the fact their starting is also spaced out by an average of half a second makes that a full second on average. There is essentially no concurrency here at all.

Categories

Resources