illustrating volatile : is this code thread-safe? - java

I'm trying to illustrate the use and importance of volatile with an example that would really not give a good result if volatile was omitted.
But I'm not really used to using volatile. The idea of the following code is to cause an infinite loop if volatile is omitted, and be perfectly thread-safe if volatile is present. Is the following code thread-safe? Do you have any other realistic and short example of code that uses volatile and would give an obviously incorrect result without it?
Here's the code:
public class VolatileTest implements Runnable {
private int count;
private volatile boolean stopped;
#Override
public void run() {
while (!stopped) {
count++;
}
System.out.println("Count 1 = " + count);
}
public void stopCounting() {
stopped = true;
}
public int getCount() {
if (!stopped) {
throw new IllegalStateException("not stopped yet.");
}
return count;
}
public static void main(String[] args) throws InterruptedException {
VolatileTest vt = new VolatileTest();
Thread t = new Thread(vt);
t.start();
Thread.sleep(1000L);
vt.stopCounting();
System.out.println("Count 2 = " + vt.getCount());
}
}

Victor is right, there are issues with your code: atomicity and visibility.
Here's my edition:
private int count;
private volatile boolean stop;
private volatile boolean stopped;
#Override
public void run() {
while (!stop) {
count++; // the work
}
stopped = true;
System.out.println("Count 1 = " + count);
}
public void stopCounting() {
stop = true;
while(!stopped)
; //busy wait; ok in this example
}
public int getCount() {
if (!stopped) {
throw new IllegalStateException("not stopped yet.");
}
return count;
}
}
If a thread observes that stopped==true, it's guaranteed that the work completes and the result is visible.
There is a happens-before relation from volatile write to volatile read (on the same variable), so if there are two threads
thread 1 thread 2
action A
|
volatile write
\
volatile read
|
action B
action A happens-before action B; writes in A are visible by B.

It was always hard to me to illustrate concurrency problems in a convincing way: well, fine, it's all nice about happens-before and stuff, but why should one care? Is there a real problem? There are lots and lots of poorly written, poorly synchronized programs—and they still work most of the time.
I used to find a resort in a "works most of the time VS works" rhetoric—but, frankly, it's a weak approach. So what I needed is an example which would make difference obvious—and, preferably, painful.
So here is a version which actually does show the difference:
public class VolatileExample implements Runnable {
public static boolean flag = true; // do not try this at home
public void run() {
long i = 0;
while (flag) {
if (i++ % 10000000000L == 0)
System.out.println("Waiting " + System.currentTimeMillis());
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new VolatileExample());
thread.start();
Thread.sleep(10000L);
flag = false;
long start = System.currentTimeMillis();
System.out.println("stopping " + start);
thread.join();
long end = System.currentTimeMillis();
System.out.println("stopped " + end);
System.out.println("Delay: " + ((end - start) / 1000L));
}
}
A simple run shows:
Waiting 1319229217263
stopping 1319229227263
Waiting 1319229242728
stopped 1319229242728
Delay: 15
That is, it takes more than ten seconds (15 here) for a running thread to notice there was any change.
With volatile, you have:
Waiting 1319229288280
stopping 1319229298281
stopped 1319229298281
Delay: 0
that is, exiting (almost) immediately. The resolution of currentTimeMillis is around 10ms, so the difference is more that 1000 times.
Note it was Apple's version of (ex-)Sun JDK, with -server option. The 10-second wait was added in order to let JIT compiler find out that the loop is hot enough, and optimize it.
Hope that helps.

Simplifying #Elf example further, where the other thread will never get the value which was updated by other thread. Removing System.out.println as there is synchronized code inside println and out is static, somehow that helps the other thread to get the latest value of flag variable.
public class VolatileExample implements Runnable {
public static boolean flag = true;
public void run() {
while (flag);
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new VolatileExample());
thread.start();
Thread.sleep(1000L);
flag = false;
thread.join();
}
}

To illustrate the importance of the volatile keyword when it comes to concurrency, all you need to do is make sure that the volatile field is modified and read in a separate threads.

UPDATE My answer is wrong, see answer from irreputable.
It's not thread-safe, since access to count is not there's only one writer thread. Should there be another writer thread, value of count would be become inconsistent to the number of updates.
Visibility of count value to main thread is ensured by checking stopped volatile inside getCount method. This is what is called piggybacking on synchronization in Concurrency in practice book.

Wrong code with which we cannot assume x = 1 also if y is already 2:
Class Reordering {
int x = 0, y = 0;
public void writer() {
x = 1;
y = 2;
}
public void reader() {
int r1 = y;
int r2 = x;
}
}
Example of use of volatile keyword:
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}
Source: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

Related

Thread.sleep behaviour with non-volatile boolean variable

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.

How to fix async java code failing even with thread safety implementation?

I am working on a codebase that implements something similar to this. We are having issues with one of the threads failing to synchronize with other threads when the value of count is incremented, thus going into an infinite loop.
The problem seems to come from the non-atomic behaviour of the post-increment operator.
You can find the code Repl here NB: You may need to run the code at least 3 times to observe it.
I need support to implement increment of count by as many threads as possible in a thread safety way.
class Main {
static volatile Integer count = new Integer(0); //boxed integer is intentional to demonstrate mutable instance
static final void Log(Object o) {
System.out.println(o);
}
static synchronized void increaseCount(){
count++;
}
static synchronized Integer getCount(){
return count;
}
public static void main(String[] arg) throws InterruptedException {
new Thread(() -> {
while (getCount() != 60) {
increaseCount();
Log(count +" thread A");
}
}).start();
new Thread(() -> {
while (getCount() != 20) {
increaseCount();
Log(count +" thread B");
}
}).start();
new Thread(() -> {
while (getCount() != 50) {
increaseCount();
Log(count+" thread C");
}
}).start();
}
}
If many threads are incrementing a shared counter, there is no guarantee about which thread will see a particular value of the counter. To make sure a particular thread sees a particular value, that thread has to see every value of the counter. And then you might as well just have one thread, because they are all working in lockstep with each other.
If you want to do some work for every value of the counter, with special handling for particular values, and you want to parallelize that workload, every thread needs to be prepared to perform the special handling. Here's an example of how you could do that:
class Main {
private static class Worker implements Runnable {
private final AtomicInteger counter;
private final Set<Integer> triggers;
Worker(AtomicInteger counter, Set<Integer> triggers) {
this.counter = counter;
this.triggers = triggers;
}
public void run() {
String name = Thread.currentThread().getName();
while (!triggers.isEmpty()) {
int value = counter.getAndIncrement();
try { /* Simulate actually doing some work by sleeping a bit. */
long delay = (long) (-100 * Math.log(1 - ThreadLocalRandom.current().nextDouble()));
TimeUnit.MILLISECONDS.sleep(delay);
} catch (InterruptedException ex) {
break;
}
boolean triggered = triggers.remove(value);
if (triggered) {
System.out.println(name + " handled " + value);
} else {
System.out.println(name + " skipped " + value);
}
}
}
}
public static void main(String[] arg) throws InterruptedException {
AtomicInteger counter = new AtomicInteger();
Set<Integer> triggers = new ConcurrentSkipListSet<>();
triggers.add(60);
triggers.add(20);
triggers.add(50);
int concurrency = 4;
ExecutorService workers = Executors.newFixedThreadPool(concurrency);
for (int i = 0; i < concurrency; ++i) {
workers.execute(new Worker(counter, triggers));
}
workers.shutdown();
}
}
The number of worker threads can be adjusted so that it makes sense given the number of cores on your machine, and the real workload (how CPU or I/O intensive the tasks are).
In this approach, each value of the counter is processed by just one thread, and it doesn't matter which thread gets a "sentinel" value. But, when all the sentinel values have been processed, all the threads shut down. Threads coordinate with each other through the counter, and the set of "triggers", or sentinel values that they need to handle.

Item 66: Synchronize access to shared mutable data [duplicate]

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 am now reading 《effective Java》 and meeting a confusion.
For code 1 (java8) :
public class StopThreadTest {
private static Boolean stopRequest = false;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
int i = 0;
while (!stopRequest) {
i++;
//System.out.println("i: " + i);
}
}).start();
TimeUnit.SECONDS.sleep(1);
stopRequest = true;
}
}
the program never terminates.
For code 2(java8):
public class StopThreadTest {
private static Boolean stopRequest = false;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
int i = 0;
while (!stopRequest) {
i++;
System.out.println("i: " + i);
}
}).start();
TimeUnit.SECONDS.sleep(1);
stopRequest = true;
}
}
Just adding System.out.println(), the program run about 1 second.
Can anybody tell me why?
System.out.println() is synchronized, removing the visibility issues with the original code. Without it, the thread can use its cached value of stopRequest and keep on running, but when println() is involved, caches are flushed and the modified value can be seen.
From PrintStream.println(String x)
synchronized (this) {
print(x);
newLine();
}
Note that this is a side-effect only. It explains the difference in behaviour, but it's not something you can rely on for correct functionality of code.

Why can't the main thread compare two variables that are updated by other threads?

I want to write two Threads that increment a number and decrement a number, and a main Thread that determines when the two numbers are equal. For example, one number starts at 0 and the other number starts at 10... When they are both 5, the main Thread should recognize they are equal and print "They meet!".
In this code, the main Thread can't not compare numup and numdown successfully:
public class Number implements Runnable {
public static int numup = 0;
public static int numdown = 10;
public Number() {
}
public static void main(String args[]) {
Number number = new Number();
Thread T1 = new Thread(number, "up");
Thread T2 = new Thread(number, "down");
T1.start();
T2.start();
while (true) {
if (numup == 5 && numdown == 5) {
System.out.println("Meet!");
System.exit(0);
}
}
}
public void run() {
while (true) {
if (Thread.currentThread().getName().equals("up")) {
numup++;
System.out.println(numup);
} else if (Thread.currentThread().getName().equals("down")) {
numdown--;
System.out.println(numdown);
}
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("wake!");
}
}
}
}
The failed result:
1
9
8
2
7
3
6
4
5
5
6
4
7
3
8
2
1
9
However, when I make the main Thread sleep a few milliseconds, it works:
public class Number implements Runnable {
public static int numup = 0;
public static int numdown = 10;
public Number() {
}
public static void main(String args[]) {
Number number = new Number();
Thread T1 = new Thread(number, "up");
Thread T2 = new Thread(number, "down");
T1.start();
T2.start();
while (true) {
try {
Thread.sleep(10);
} catch (Exception e) {
System.out.println(Thread.currentThread().getName() + "was waked!");
}
if (numup == 5 && numdown == 5) {
System.out.println("They Meet!");
System.exit(0);
}
}
}
public void run() {
while (true) {
if (Thread.currentThread().getName().equals("up")) {
numup++;
System.out.println(numup);
} else if (Thread.currentThread().getName().equals("down")) {
numdown--;
System.out.println(numdown);
}
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("wake!");
}
}
}
}
The successful result:
1
9
2
8
3
7
4
6
5
5
They Meet!
Why does the added delay make it work?
This could be because of the CPU cache. When the number thread updates the value of the variable (this goes from its CPU cache to main memory) by then the CPU cache of the corresponding main thread might not have got updated.
So when main thread check's the value of the variable it was still the old value.
You can use Volatile. OR
Use AtomicInteger for these operations.
You can refer to this link.
In a multithreaded application where the threads operate on non-volatile variables, each thread may copy variables from main memory into a CPU cache while working on them, for performance reasons. If your computer contains more than one CPU, each thread may run on a different CPU. That means, that each thread may copy the variables into the CPU cache of different CPUs.
With non-volatile variables there are no guarantees about when the Java Virtual Machine (JVM) reads data from main memory into CPU caches, or writes data from CPU caches to main memory.
Volatile:
public static volatile int numup = 0;
public static volatile int numdown = 10;
Atomic Integer:
import java.util.concurrent.atomic.AtomicInteger;
public class Number implements Runnable {
public static AtomicInteger numup = new AtomicInteger(0);
public static AtomicInteger numdown = new AtomicInteger(10);
public Number() {
}
public static void main(String args[]) {
Number number = new Number();
Thread T1 = new Thread(number, "up");
Thread T2 = new Thread(number, "down");
T1.start();
T2.start();
while (true) {
if (numup.get() == 5 && numdown.get() == 5) {
System.out.println("Meet!");
System.exit(0);
}
}
}
public void run() {
while (true) {
if (Thread.currentThread().getName().equals("up")) {
numup.incrementAndGet();
System.out.println(numup);
} else if (Thread.currentThread().getName().equals("down")) {
numdown.decrementAndGet();
System.out.println(numdown);
}
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("wake!");
}
}
}
}
Quick answer - add volatile modifier to numdown and numup.
Long answer:
Your problem is that other thread can't see that numdown and numup has changed because of couple of reasons:
JVM may optimize and reorder the execution order of bytecode instructions.
Modern processors also do instruction reordering.
The value is cached in processor's cache line (L1, L2, L3 cache level).
So, when you introduce a volatile variable it is guaranteed by java that writes from one thread will have happen-before relationships with reads form another thus making changes visible to the another thread. On more low-level it could introduce a memory barrier
Anyway, it would not fit into the SO answer to explain properly how it's works, but there is a number of excellent resources you could read/watch if you're interested to dive deeper into the topic.
https://zeroturnaround.com/rebellabs/java-memory-model-pragmatics-by-aleksey-shipilev/
Do you ever use the volatile keyword in Java?
http://mechanical-sympathy.blogspot.com/2011/07/memory-barriersfences.html
Cheers!
Interesting one and a good answer given by Yegor. Just to add my observation that the program halts even if you write the if (numup == 5 && numdown == 5) check inside the while loop of the run() method.
In case you want to try out with the volatile keyword.
public static volatile int numup = 0;
public static volatile int numdown = 10;
volatile keyword will ensure that your threads won't cache the value of the variable and will always retrieve it from the main memory.

volatile keyword seems to be useless?

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class Main implements Runnable {
private final CountDownLatch cdl1 = new CountDownLatch(NUM_THREADS);
private volatile int bar = 0;
private AtomicInteger count = new AtomicInteger(0);
private static final int NUM_THREADS = 25;
public static void main(String[] args) {
Main main = new Main();
for(int i = 0; i < NUM_THREADS; i++)
new Thread(main).start();
}
public void run() {
int i = count.incrementAndGet();
cdl1.countDown();
try {
cdl1.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
bar = i;
if(bar != i)
System.out.println("Bar not equal to i");
else
System.out.println("Bar equal to i");
}
}
Each Thread enters the run method and acquires a unique, thread confined, int variable i by getting a value from the AtomicInteger called count. Each Thread then awaits the CountDownLatch called cdl1 (when the last Thread reaches the latch, all Threads are released). When the latch is released each thread attempts to assign their confined i value to the shared, volatile, int called bar.
I would expect every Thread except one to print out "Bar not equal to i", but every Thread prints "Bar equal to i". Eh, wtf does volatile actually do if not this?
It is a deliberate intention that each Thread attempts to set the value of bar at exactly the same time.
EDIT:
In light of the answer, changed code to this:
...
bar = i;
try {
Thread.sleep(0);
} catch(InterruptedException e) {
e.printStackTrace();
}
...
To ensure that a little time is wasted between the set and read of the variable.
Now the print is 50/50 on same/different value for Bar.
The JVM decides when the threads run, not you. If it felt like holding one of the ones whose latch just released for another 10ms, just because, it can do that. After the latch releases, they still have to wait for their turn to execute. Unless you're running it on a 25 core computer, they're not all assigning bar at anywhere near 'the same time' down inside the machine. Since all you're doing is a couple of primitive operations, it's extremely unlikely that one of them won't finish inside its time slice before the next one gets released!
It's not. You're misusing it. There is a great article here by Herb Sutter that explains it in more detail.
The basic idea is that volatile makes variables unoptimisable. It does not make them thread safe.
To answer the 'WTF does volatile actually do?':
volatile is all about visibility. In Java's thread model, if a thread A writes into a regular shared field, there is no guarantee that a thread B will ever see the value written by A, unless the threads are synchronized somehow. volatile is one of the synchronization mechanisms.
Unlike non-volatile fields, when thread A writes into a volatile field and thread B later reads it, B is guaranteed to see the new value and not an older version.
(Actually volatile does even more - thread B will not only see the new value of the field, but everything else written by A before it set the volatile variable as well. It established a happened-before relationship).
What you should do is replace your instance of volatile int with AtomicInteger. See here.
I think you meant to write this:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class Main implements Runnable {
private final CountDownLatch cdl1 = new CountDownLatch(NUM_THREADS);
private volatile int bar = 0;
private AtomicInteger count = new AtomicInteger(0);
private static final int NUM_THREADS = 25;
public static void main(String[] args) {
Main main = new Main();
for(int i = 0; i < NUM_THREADS; i++)
new Thread(main).start();
}
public void run() {
int i = count.incrementAndGet();
bar = i;
cdl1.countDown();
try {
cdl1.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if(bar != i)
System.out.println("Bar not equal to i");
else
System.out.println("Bar equal to i");
}
}
Which prints "Bar not equal to i" like you expected.

Categories

Resources