Why does marking a Java variable volatile make things less synchronized? - java

So I just learned about the volatile keyword while writing some examples for a section that I am TAing tomorrow. I wrote a quick program to demonstrate that the ++ and -- operations are not atomic.
public class Q3 {
private static int count = 0;
private static class Worker1 implements Runnable{
public void run(){
for(int i = 0; i < 10000; i++)
count++; //Inner class maintains an implicit reference to its parent
}
}
private static class Worker2 implements Runnable{
public void run(){
for(int i = 0; i < 10000; i++)
count--; //Inner class maintains an implicit reference to its parent
}
}
public static void main(String[] args) throws InterruptedException {
while(true){
Thread T1 = new Thread(new Worker1());
Thread T2 = new Thread(new Worker2());
T1.start();
T2.start();
T1.join();
T2.join();
System.out.println(count);
count = 0;
Thread.sleep(500);
}
}
}
As expected the output of this program is generally along the lines of:
-1521
-39
0
0
0
0
0
0
However, when I change:
private static int count = 0;
to
private static volatile int count = 0;
my output changes to:
0
3077
1
-3365
-1
-2
2144
3
0
-1
1
-2
6
1
1
I've read When exactly do you use the volatile keyword in Java? so I feel like I've got a basic understanding of what the keyword does (maintain synchronization across cached copies of a variable in different threads but is not read-update-write safe). I understand that this code is, of course, not thread safe. It is specifically not thread-safe to act as an example to my students. However, I am curious as to why adding the volatile keyword makes the output not as "stable" as when the keyword is not present.

Why does marking a Java variable volatile make things less synchronized?
The question "why does the code run worse" with the volatile keyword is not a valid question. It is behaving differently because of the different memory model that is used for volatile fields. The fact that your program's output tended towards 0 without the keyword cannot be relied upon and if you moved to a different architecture with differing CPU threading or number of CPUs, vastly different results would not be uncommon.
Also, it is important to remember that although x++ seems atomic, it is actually a read/modify/write operation. If you run your test program on a number of different architectures, you will find different results because how the JVM implements volatile is very hardware dependent. Accessing volatile fields can also be significantly slower than accessing cached fields -- sometimes by 1 or 2 orders of magnitude which will change the timing of your program.
Use of the volatile keyword does erect a memory barrier for the specific field and (as of Java 5) this memory barrier is extended to all other shared variables. This means that the value of the variables will be copied in/out of central storage when accessed. However, there are subtle differences between volatile and the synchronized keyword in Java. For example, there is no locking happening with volatile so if multiple threads are updating a volatile variable, race conditions will exist around non-atomic operations. That's why we use AtomicInteger and friends which take care of increment functions appropriately without synchronization.
Here's some good reading on the subject:
Java theory and practice: Managing volatility
The volatile keyword in Java
Hope this helps.

An educated guess at what you're seeing - when not marked as volatile the JIT compiler is using the x86 inc/dec operations which can update the variable atomically. Once marked volatile these operations are no longer used and the variable is instead read, incremented/decremented, and then finally written causing more "errors".
The non-volatile setup has no guarantees it'll function well though - on a different architecture it could be worse than when marked volatile. Marking the field volatile does not begin to solve any of the race issues present here.
One solution would be to use the AtomicInteger class, which does allow atomic increments/decrements.

Volatile variables act as if each interaction is enclosed in a synchronized block. As you mentioned, increment and decrement is not atomic, meaning each increment and decrement contains two synchronized regions (the read and the write). I suspect that the addition of these pseudolocks is increasing the chance that the operations conflict.
In general the two threads would have a random offset from another, meaning that the likelihood of either one overwriting the other is even. But the synchronization imposed by volatile may be forcing them to be in inverse-lockstep, which, if they mesh together the wrong way, increases the chance of a missed increment or decrement. Further, once they get in this lockstep, the synchronization makes it less likely that they will break out of it, increasing the deviation.

I stumbled upon this question and after playing with the code for a little bit found a very simple answer.
After initial warm up and optimizations (the first 2 numbers before the zeros) when the JVM is working at full speed T1 simply starts and finishes before T2 even starts, so count is going all the way up to 10000 and then to 0.
When I changed the number of iterations in the worker threads from 10000 to 100000000 the output is very unstable and different every time.
The reason for the unstable output when adding volatile is that it makes the code much slower and even with 10000 iterations T2 has enough time to start and interfere with T1.

The reason for all those zeroes is not that the ++'s and --'s are balancing each other out. The reason is that there is nothing here to cause count in the looping threads to affect count in the main thread. You need synch blocks or a volatile count (a "memory barrier) to force the JVM to make everything see the same value. With your particular JVM/hardware, what is most likely happening that the value is kept in a register at all times and never getting to cache--let alone main memory--at all.
In the second case you are doing what you intended: non-atomic increments and decrements on the same course and getting results something like what you expected.
This is an ancient question, but something needed to be said about each thread keeping it's own, independent copy of the data.

If you see a value of count that is not a multiple of 10000, it just shows that you have a poor optimiser.

It doesn't 'make things less synchronized'. It makes them more synchronized, in that threads will always 'see' an up to date value for the variable. This requires erection of memory barriers, which have a time cost.

Related

Trying to understand shared variables in java threads

I have the following code :
class thread_creation extends Thread{
int t;
thread_creation(int x){
t=x;
}
public void run() {
increment();
}
public void increment() {
for(int i =0 ; i<10 ; i++) {
t++;
System.out.println(t);
}
}
}
public class test {
public static void main(String[] args) {
int i =0;
thread_creation t1 = new thread_creation(i);
thread_creation t2 = new thread_creation(i);
t1.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
}
}
When I run it , I get :
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
Why I am getting this output ? According to my understanding , the variable i is a shared variable between the two threads created. So according to the code , the first thread will execute and increments i 10 times , and hence , i will be equal to 10 . The second thread will start after the first one because of the sleep statement and since i is shared , then the second thread will start will i=10 and will start incrementing it 10 times to have i = 20 , but this is not the case in the output , so why that ?
You seem to think that int t; in thread_creation is a shared variable. I'm afraid you are mistaken. Each t instance is a different variable. So the two threads are updating distinct counters.
The output you are seeing reflects that.
This is the nub of your question:
How do I pass a shared variable then ?
Actually, you can't1. Strictly a shared variable is actually a variable belonging to a shared object. You cannot pass a variable per se. Java does not allow passing of variables. This is what "Java does not support call-by-reference" really means. You can't pass or return a variable or the address of a variable in any method call. (Or in any other way.)
In Java you pass and return values: either primitives, or references to objects. The values may read from a variable by the call's parameter expression or assigned to a variable after the call's return. But you are not passing the variable. A variable and its value / contents are different things.
So the only way to implement a shared counter is to implement it as a shared counter object.
Note that "variable" and "object" mean different things, both in Java and in other programming languages. You should NOT use the two terms interchangeable. For example, when I declare this in Java:
String s = "Hello";
the s variable is not a String object. It is a variable that contains a reference to the String object. Other variables may contain references to the same String object as well. The distinction is even more stark when the objects are mutable. (String is not mutable ... in Java.)
Here are the two (IMO) best ways to implement a shared counter object.
You could create a custom Java Counter class with a count variable, a get method, and methods for incrementing, decrementing the counter. The class needs to implement various methods as thread-safe and atomic; e.g. by using synchronized methods or blocks2.
You could just use an AtomicInteger instance. That takes care of atomicity and thread-safety ... to the extent that it is possible with this kind of API.
The latter approach is simpler and likely more efficient ... unless you need to do something special each time the counter changes.
(It is conceivable that you could implement a shared counter other ways, but that is too much detail for this answer.)
1 - I realize that I just said the same thing more than 3 times. But as the Bellman says in "The Hunting of the Snark": "What I tell you three times is true."
2 - If the counter is not implemented using synchronized or an equivalent mutual exclusion mechanism with the appropriate happens before semantics, you are liable to see Heisenbugs; e.g. race conditions and memory visibility problems.
Two crucial things you're missing. Both individually explain this behaviour - you can 'fix' either one and you'll still see this, you'd have to fix both to see 1-20:
Java is pass-by-value
When you pass i, you pass a copy of it. In fact, in java, all parameters to methods are always copies. Hence, when the thread does t++, it has absolutely no effect whatsoever on your i. You can trivially test this, and you don't need to mess with threads to see it:
public static void main(String[] args) {
int i = 0;
add5(i);
System.out.println(i); // prints 0!!
}
static void add5(int i) {
i = i + 5;
}
Note that all non-primitives are references. That means: A copy of the reference is passed. It's like passing the address of a house and not the house itself. If I have an address book, and I hand you a scanned copy of a page that contains the address to my summer home, you can still drive over there and toss a brick through the window, and I'll 'see' that when I go follow my copy of the address. So, when you pass e.g. a list and the method you passed the list to runs list.add("foo"), you DO see that. You may think: AHA! That means java does not pass a copy, it passed the real list! Not so. Java passed a copy of a street address (A reference). The method I handed that copy to decided to drive over there and act - that you can see.
In other words, =, ++, that sort of thing? That is done to the copy. . is java for 'drive to the address and enter the house'. Anything you 'do' with . is visible to the caller, = and ++ and such are not.
Fixing the code to avoid the pass-by-value problem
Change your code to:
class thread_creation extends Thread {
static int t; // now its global!
public void run() {
increment();
}
public void increment() {
for(int i =0 ; i<10 ; i++) {
t++;
// System.out.println(t);
}
}
}
public class test {
public static void main(String[] args) throws Exception {
thread_creation t1 = new thread_creation();
thread_creation t2 = new thread_creation();
t1.start();
Thread.sleep(500);
t2.start();
Thread.sleep(500);
System.out.println(thread_creation.t);
}
}
Note that I remarked out the print line. I did that intentionally - see below. If you run the above code, you'd think you see 20, but depending on your hardware, the OS, the song playing on your mp3 playing app, which websites you have open, and the phase of the moon, it may be less than 20. So what's going on there? Enter the...
The evil coin.
The relevant spec here is the JMM (The Java Memory Model). This spec explains precisely what a JVM must do, and therefore, what a JVM is free not to do, especially when it comes to how memory is actually managed.
The crucial aspect is the following:
Any effects (updates to fields, such as that t field) may or may not be observable, JVM's choice. There's no guarantee that anything you do is visible to anything else... unless there exists a Happens-Before/Happens-After relationship: Any 2 statements with such a relationship have the property that the JVM guarantees that you cannot observe the lack of the update done by the HB line from the HA line.
HB/HA can be established in various ways:
The 'natural' way: Anything that is 'before' something else _and runs in the same thread has an HB/HA relationship. In other words, if you do in one thread x++; System.out.println(x); then you can't observe that the x++ hasn't happened yet. It's stated like this so that if you're not observing, you get no guarantees, which gives the JVM the freedom to optimize. For example, Given x++;y++; and that's all you do, the JVM is free to re-order that and increment y before x. Or not. There are no guarantees, a JVM can do whatever it wants.
synchronized. The moment of 'exiting' a synchronized (x) {} block has HB to the HA of another thread 'entering' the top of any synchronized block on the same object, if it enters later.
volatile - but note that with volatile it's basically impossible which one came first. But one of them did, and any interaction with a volatile field is HB relative to another thread accessing the same field later.
thread starting. thread.start() is HB relative to the first line of the run() of that thread.
thread yielding. thread.yield() is HA relative to the last line of the thread.
There are a few more exotic ways to establish HB/HA but that's pretty much it.
Crucially, in your code there is no HB/HA between any of the statements that modify or print t!
In other words, the JVM is free to run it all in such a way that the effects of various t++ statements run by one thread aren't observed by another thread.
What the.. WHY????
Because of efficiency. Your memory banks on your CPU are, relative to how fast CPUs are, oceans away from the CPU core. Fetching or writing to core memory from a CPU takes an incredibly long time - your CPU is twiddling its thumbs for a very long time while it waits for the memory controller to get the job done. It could be running hundreds of instructions in that time.
So, CPU cores do not write to memory AT ALL. Instead they work with caches: They have an on-core cache page, and the only interaction with your main memory banks (which are shared by CPU cores) is 'load in an entire cache page' and 'write an entire cache page'. That cache page is then effectively a 'local copy' that only that core can see and interact with (but can do so very very quickly, as that IS very close to the core, unlike the main memory banks), and then once the algorithm is done it can flush that page back to main memory.
The JVM needs to be free to use this. Had the JVM actually worked like you want (that anything any thread does is instantly observable by all others), then anything that any line does must first wait 500 cycles to load the relevant page, then wait another 500 cycles to write it back. All java apps would literally be 1000x slower than they could be.
This in passing also explains that actual synchronizing is really slow. Nothing java can do about that, it is a fundamental limitation of our modern multi-core CPUs.
So, evil coin?
Note that the JVM does not guarantee that the CPU must neccessarily work with this cache stuff, nor does it make any promises about when cache pages are flushed. It merely limits the guarantees so that JVMs can be efficiently written on CPUs that work like that.
That means that any read or write to any field any java code ever does can best be thought of as follows:
The JVM first flips a coin. On heads, it uses a local cached copy. On tails, it copies over the value from some other thread's cached copy instead.
The coin is evil: It is not reliably a 50/50 arrangement. It is entirely plausible that throughout developing a feature and testing it, the coin lands tails every time it is flipped. It remains flipping tails 100% of the time for the first week that you deployed it. And then just when that big potential customer comes in and you're demoing your app, the coin, being an evil, evil coin, starts flipping heads a few times and breaking your app.
The correct conclusion is that the coin will mess with you and that you cannot unit test against it. The only way to win the game is to ensure that the coin is never flipped.
You do this by never touching a field from multiple threads unless it is constant (final, or simply never changes), or if all access to it (both reads and writes) has clearly established HB/HA between all threads.
This is hard to do. That's why the vast majority of apps don't do it at all. Instead, they:
Talk between threads using a database, which has vastly more advanced synchronization primitives: Transactions.
Talk using a message bus such as RabbitMQ or similar.
Use stuff from the java.util.concurrent package such as a Latch, ForkJoin, ConcurrentMap, or AtomicInteger. These are easier to use (specifically: It is a lot harder to write code for these abstractions that is buggy but where the bug cannot be observed or tested for on the machine of the developer that wrote it, it'll only blow up much later in production. But not impossible, of course).
Let's fix it!
volatile doesn't 'fix' ++. x++; is 'read x, increment by 1, write result to x' and volatile doesn't make that atomic, so we cannot use this. We can either replace t++ with:
synchronized(thread_creation.class) {
t++;
}
Which works fine but is really slow (and you shouldn't lock on publicly visible stuff if you can help it, so make a custom object to lock on, but you get the gist hopefully), or, better, dig into that j.u.c package for something that seems useful. And so there is! AtomicInteger!
class thread_creation extends Thread {
static AtomicInteger t = new AtomicInteger();
public void run() {
increment();
}
public void increment() {
for(int i =0 ; i<10 ; i++) {
t.incrementAndGet();
}
}
}
public class test {
public static void main(String[] args) throws Exception {
thread_creation t1 = new thread_creation();
thread_creation t2 = new thread_creation();
t1.start();
Thread.sleep(500);
t2.start();
Thread.sleep(500);
System.out.println(thread_creation.t.get());
}
}
That code will print 20. Every time (unless those threads take longer than 500msec which technically could be, but is rather unlikely of course).
Why did you remark out the print statement?
That HB/HA stuff can sneak up on you: When you call code you did not write, such as System.out.println, who knows what kind of HB/HA relationships are in that code? Javadoc isn't that kind of specific, they won't tell you. Turns out that on most OSes and JVM implementations, interaction with standard out, such as System.out.println, causes synchronization; either the JVM does it, or the OS does. Thus, introducing print statements 'to test stuff' doesn't work - that makes it impossible to observe the race conditions your code does have. Similarly, involving debuggers is a great way to make that coin really go evil on you and flip juuust so that you can't tell your code is buggy.
That is why I remarked it out, because with it in, I bet on almost all hardware you end up seeing 20 eventhough the JVM doesn't guarantee it and that first version is broken. Even if on your particular machine, on this day, with this phase of the moon, it seems to reliably print 20 every single time you run it.

Thread safety in java multithreading

I found code about thread safety but it doesn't have any explanation from the person who gave the example. I would like to understand why if I don't set the "synchronized" variable before "count" that the count value will be non-atomic ( always =200 is the desired result). Thanks
public class Example {
private static int count = 0;
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
//add synchronized
synchronized (Example.class){
count++;
}
}
}).start();
}
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(count);
}
}
++ is not atomic
The count++ operation is not atomic. That means it is not a single solitary operation. The ++ is actually three operations: load, increment, store.
First the value stored in the variable is loaded (copied) into a register in the CPU core.
Second, that value in the core’s register is incremented.
Third and last, the new incremented value is written (copied) from the core’s register back to the variable’s content in memory. The core’s register is then free to be assigned other values for other work.
It is entirely possible for two or more threads to read the same value for the variable, say 42. Each of those threads would then proceed to increment the value to the same new value 43. They would then each write back 43 to that same variable, unwittingly storing 43 again and again repeatedly.
Adding synchronized eliminates this race condition. When the first thread gets the lock, the second and third threads must wait. So the first thread is guaranteed to be able to read, increment, and write the new value alone, going from 42 to 43. Once completed, the method exits, thereby releasing the lock. The second thread vying for the lock gets the go-ahead, acquiring the lock, and is able to read, increment, and write the new value 44 without interference. And so on, thread-safe.
Another problem: Visibility
However, this code is still broken.
This code has a visibility problem, with various threads possibly reading stale values kept in caches. But that is another topic. Search to learn more about volatile keyword, the AtomicInteger class, and the Java Memory Model.
I would like to understand why if I don't set the "synchronized" variable before "count" that the count value will be non-atomic.
The short answer: Because the JLS says so!
If you don't use synchronized (or volatile or something similar) then the Java Language Specification (JLS) does not guarantee that the main thread will see the values written to count by the child thread.
This is specified in great detail in the Java Memory Model section of the JLS. But the specification is very technical.
The simplified version is that a read of a variable is not guaranteed to see the value written by a preceding write if there is not a happens before (HB) relationship connecting the write and the read. Then there are a bunch of rules that say when an HB relationship exists. One of the rules is that there is an HB between on thread releasing a mutex and a different thread acquiring it.
An alternative intuitive (but incomplete and technically inaccurate) explanation is that the latest value of count may be cached in a register or a chipset's memory caches. The synchronized construct flushes values to be memory.
The reason that is an inaccurate explanation is that JLS doesn't say anything about registers, caches and so on. Rather, the memory visibility guarantees that the JLS specifies are typically implemented by a Java compiler inserting instructions to write registers to memory, flush caches, or whatever is required by the hardware platform.
The other thing to note is that this is not really about count++ being atomic or not1. It is about whether the result of a change to count is visible to a different thread.
1 - It isn't atomic, but you would get the same effect for an atomic operation like a simple assignment!
Let's get back to the basics with a Wall Street example.
Let's say, You (Lets call T1 ) and your friend (Lets call T2) decided to meet at a coffee house on Wall Street. You both started at same time, let's say from southern end of the Wall Street (Though you are not walking together). You are waking on one side of footpath and your friend is walking on other side of the footpath on Wall Street and you both going towards North (Direction is same).
Now, let's say you came in front of a coffee house and you thought this is the coffee house you and your friend decided to meet, so you stepped inside the coffee house, ordered a cold coffee and started sipping it while waiting.
But, On other side of the road, similar incident happened, your friend came across a coffee shop and ordered a hot chocolate and was waiting for you.
After a while, you both decided the other one is not going to come dropped the plan for meeting.
You both missed your destination and time. Why was this happened? Don't have to mention but, Because you did not decided the exact venue.
The code
synchronized(Example.class){
counter++;
}
solves the problem that you and your friend just encountered.
In technical terms the operation counter++ is actually conducted in three steps;
Step 1: Read the value of counter (lets say 1)
Step 2: Add 1 in to the value of counter variable.
Step 3: Write the value of the variable counter back to memory.
If two threads are working simultaneously on counter variable, final value of the counter will be uncertain. For example, Thread1 could read the value of the counter as 1, at the same time thread2 could read the value of variable as 1. The both threads endup incrementing the value of counter to 2. This is called race condition.
To avoid this issue, the operation counter++ has to be atomic. To make it atomic you need to synchronize execution of the thread. Each thread should modify the counter in organized manner.
I suggest you to read book Java Concurrency In Practice, every developer should read this book.

Can't understand example of volatile in Java specification

I got general understanding what volatile means in Java. But reading
Java SE Specification 8.3.1.4 I have a problem understanding the text beneath that certain volatile example.
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
This allows method one and method two to be executed concurrently, but
guarantees that accesses to the shared values for i and j occur
exactly as many times, and in exactly the same order, as they appear
to occur during execution of the program text by each thread.
Therefore, the shared value for j is never greater than that for i,
because each update to i must be reflected in the shared value for i
before the update to j occurs. It is possible, however, that any given
invocation of method two might observe a value for j that is much
greater than the value observed for i, because method one might be
executed many times between the moment when method two fetches the
value of i and the moment when method two fetches the value of j.
How is
j never greater than i
, but at the same time
any given invocation of method two might observe a value for j that is
much greater than the value observed for i
??
Looks like contradiction.
I got j greater than i after running sample program. Why use volatile then? It gives almost the same result without volatile (also i can be greater than j, one of previous examples in specs). Why is this example here as an alternative to synchronized?
At any one time, then j is not greater than i.
This is different from what method two observes because it is accessing the variables i and j at different times. i is accessed first, and then j is accessed slightly later.
This isn't a direct alternative to the synchronized version because the behavior is different. One difference from not using volatile is that without volatile, values of 0 could always be printed. The increment doesn't ever need to be visible.
The example demonstrates the ordering of volatile accesses. An example that requires this could be something like:
volatile boolean flag = false;
volatile int value;
// Thread 1
if(!flag) {
value = ...;
flag = true;
}
// Thread 2
if(flag) {
System.out.println(value);
flag = false;
}
and thread 2 reads the value that thread 1 set rather than an old value.
I'd like to propose that it's a mistake and the examples were supposed to print j before i:
static void two() {
System.out.println("j=" + j + " i=" + i);
}
The novelty in the first example is that, due to update reordering, j can be greater than i even when observed first.
The final example now makes perfect sense with some minor edits to the explanation (edits and commentary in brackets):
This allows method one and method two to be executed concurrently, but guarantees that accesses to the shared values for i and j occur exactly as many times, and in exactly the same order, as they appear to occur during execution of the program text by each thread. Therefore, the shared value for j is never [observed to be] greater than that for i, because each update to i must be reflected in the shared value for i before the update to j occurs. It is possible, however, that any given invocation of method two might observe a value for [i] that is much greater than the value observed for [j], because method one might be executed many times between the moment when method two fetches the value of [j] and the moment when method two fetches the value of [i].
The key point here is that the second update will never be observed before the first update, when using volatile. The last sentence about the gap between the two reads is entirely parenthetical, and i and j were swapped to conform to the erroneous example.
I think the point of the example is to emphasize that you need to take care and ensure the order when using volatile; the behavior may be counter-intuitive and the example demonstrates it.
I agree that the wording there is a bit obscure and it is possible to provide more explicit and clear example for multiple cases, but there is no contradiction.
The shared value is the value at the same moment. If two threads read values of i and of j at exactly the same moment, the value of j will never be observed greater than i. volatile guarantees keeping order of reads and updates as in the code.
However, in the sample, print + i and + j are two different operations separated by an arbitrary amount of time; hence, j can be observed larger than i, because it can be updated arbitrary number of times after the read of i and before the read of j.
The point of using volatile is that when you concurrently update and access volatile variables with the right order, you can make assumptions that are not possible in principle without volatile.
In the sample above, the order of access in two() does not allow to conclude with a confidence which variable is greater or equal.
Consider, however, if the sample was changed to System.out.println("j=" + j + " i=" + i);
Here you can assert with a confidence that the printed value of j is never larger than the printed value of i. This assumption will not hold without volatile for two reasons.
First, updates i++ and j++ can be executed by compiler and hardware in an arbitrary order and in reality may execute as j++;i++. If from other thread you then access j and i after j++ but before i++, you can observe, say, j=1 and i=0, regardless of the access order. volatile guarantees that this will not happen and it will execute operations in the order that is written in your source.
Second, volatile guarantees that another thread will see most recent values changed by another thread, as long as it accesses it in the later point of time after the last update. Without volatile, there can be no assumptions about the observed value. In theory, the value can stay for another thread zero forever. The program may print two zeros, zero and an arbitrary number, etc. from past updates; the observed value in other threads may be less than the current value that the updater thread sees after an update. volatile guarantees that you will see the value in a second thread after the update in the first.
While the second guarantee may seem as a consequence of the first (the order guarantee), they are in fact orthogonal.
Regarding synchronized, it allows to execute a sequence of non-atomic operations, like i++;j++ as an atomic operation, e.g. if one thread does synchronized i++;j++ and another does synchronized System.out.println("i=" + i + " j=" + j);, the first thread may not perform increment sequence while the second prints and the result will be correct.
But this comes at a cost. First, synhronized has a performance penalty by itself. Second, more important, not always such behavior is required and the blocked thread wastes time, reducing the system throughput (e.g. you can do so many i++;j++; during System.out).
How is j never greater than i?
Let's say you execute one() only once. During the execution of this method, i is always incremented before j as the increment operations happen one after the other.
If you are executing one() concurrently, each individual method call will wait for other methods in the execution queue to finish writing their values to i or j, depending on which variable the currently executing method is trying to increment. So, all writes to i happen one after the other, and all writes to j happen one after the other. And since within the method body itself i is incremented before j, at a given instant, j will never be greater than i.
any given invocation of method two might observe a value for j that is much greater than the value observed for i, how?
If method one() is being executed in the background while you call two(), between the time when i is read and then j is read, the method one can be executed multiple times. So, when the value of i is read it could be the result some invocation of one() that happened at time t=0, and when then value of j is read, it could be the result of an invocation of one() that happened later in time, for example at t=10. Hence, j can be greater than i in this case in the println statement.
Why use volatile in lieu of synchronized?
I will not list all the reasons why anyone should use volatile instead of a synchronized block. But bear in mind that volatile guarantees atomic access to that particular field alone, and does not ensure the atomic execution of a block of code that is not marked as synchronized. In this example, access to i and j are synchronized, but the overall operation {i++;j++} isn't synchronized hence it apparently (I use apparently since it is not exactly the same but looks similar) gives the same results as without using the volatile keyword.
How is
j never greater than i
, but at the same time
any given invocation of method two might observe a value for j that is much >>greater than the value observed for i
??
The first statement is always true at any given moment in the program's execution, and the second statement may be true for any given interval in the program's execution.
When a volatile variable is written to, writes to both it and everything before it must become visible to other threads (In Java 5+, at least. The explanation doesn't really change much for versions of Java before that, though). Thus, the increment of i must be visible by the time j is incremented, meaning that j can never appear greater than i to other threads.
The reads of i and j, though, are not guaranteed to occur at a single moment in the program execution. The read of i and j may appear to occur very close to each other to the thread executing two(), but in reality some arbitrary amount of time may have passed between the reads. For example, two() may read i when i = 5 and j = 5, but then get "frozen" while other threads execute, changing the values of i and j to, say, 20 and 19, respectively. When two() resumes, it picks up where it left off and reads j, which now has a value of 19. two() doesn't re-read i because as far as it is concerned there was no break in execution, so there is no need to undergo the extra work.
Why use volatile then?
While both volatile and synchronized provide visibility guarantees, the precise semantics are slightly different. volatile guarantees that changes made to the variable will be instantly visible to all threads, while synchronized guarantees that changes made in its block will be visible to all threads as long as they synchronize on the same lock. synchronized also provides additional atomicity guarantees that volatile does not.
Why is this example here as an alternative to synchronized?
volatile is a viable alternative to synchronized only if one() is executed by a single thread, which is the case here. In this case, only a single thread is ever writing to i and j, so there is no need for the atomicity guarantees synchronized provides. If one() were executed by multiple threads, volatile wouldn't work because the read-add-store operations that make up an increment must occur atomically, and volatile does not guarantee that.
This program does guarantee that method two() observes j >= i-1 (not considering overflow).
Without volatile, the observed values of i,j could be all over the place.
The statement
the shared value for j is never greater than that for i
is very informal, because it means "at the same time", which is not a defined concept in JMM.
The core principle of JMM is about "sequential consistency". The driving motivation of JMM is
JLS#17 - If a program is correctly synchronized, then all executions of the program will appear to be sequentially consistent
In the following program
void f()
{
int x=0, y=0;
x++;
print( x>y );
y++
}
x>y will always be observed as true. It has to be, if we follow the sequence of actions. Otherwise, there is really no way for us to reason about any (imperative) code. That is "sequential consistency".
"Sequential consistency" is an observed property, it doesn't have to coincide with "real" actions (whatever that means). It is entirely possible that x>y is evaluated to be true by JVM before x is actually incremented (or at all). As long as JVM can guarantee observed sequential consistency, it can optimize actual execution anyway it can, e.g. execute code out of order.
But this is for a singlet thread. If multiple threads are reading/writing shared variables, such optimizations of course will completely wreck sequential consistency. We cannot reason about program behavior by thinking of interleaving actions from multiple threads (with actions in the same thread following intra-thread sequence).
If we want to guarantee inter-thread sequential consistency of any multi-thread code, we must abandon the optimization techniques developed for single thread. That is going to have severe performance penalty for most programs. And it is also uncalled for -- data exchange among threads is rather rare.
Therefore, special instructions are created just for establishing inter-thread sequential consistency when it is needed. Volatile reads and writes are such actions. All volatile reads and writes obey inter-thread sequential consistency. In this case, it guarantees that j >= i-1 in two().
All dependes on how you are using it. The volatile keyword in Java is used as an indicator to Java compiler and Thread that do not cache value of this variable and always read it from main memory. So if you want to share any variable in which read and write operation is atomic by implementation e.g. read and write in an int or a boolean variable then you can declare them as volatile variable.
From Java 5 along with major changes like Autoboxing, Enum, Generics and Variable arguments , Java introduces some change in Java Memory Model (JMM), Which guarantees visibility of changes made from one thread to another also as "happens-before" which solves the problem of memory writes that happen in one thread can "leak through" and be seen by another thread.
The Java volatile keyword cannot be used with method or class and it can only be used with a variable. Java volatile keyword also guarantees visibility and ordering, after Java 5 write to any volatile variable happens before any read into the volatile variable. By the way use of volatile keyword also prevents compiler or JVM from the reordering of code or moving away them from synchronization barrier.
Important points on Volatile keyword in Java
The volatile keyword in Java is only application to a variable and using volatile keyword with class and method is illegal.
volatile keyword in Java guarantees that value of the volatile variable will always be read from main memory and not from Thread's local cache.
In Java reads and writes are atomic for all variables declared using Java volatile keyword (including long and double variables).
Using the volatile keyword in Java on variables reduces the risk of memory consistency errors because any write to a volatile variable in Java establishes a happens-before relationship with subsequent reads of that same variable.

Atomicity of increment operation

I am learning multi-thread programming from 'Java Concurrency in Practice'.
At one point, book says that even an innocuous looking increment operation is not thread safe as it consists of three different operations...read,modify and write.
class A {
private void int c;
public void increment() {
++c;
}
}
So increment statement is not atomic, hence not thread safe.
My question is that if an environment is really concurrent (ie multiple threads are able to execute their program statements exactly at same time) then a statement which is really atomic also can't be thread safe as multiple threads can read same value.
So how can having an atomic statement help in achieving thread safety in a concurrent environment?
True concurrency does not exist when it comes to modifying state.
This post has some good descriptions of Concurrency and Parallelism.
As stated by #RitchieHindle in that post:
Concurrency is when two tasks can start, run, and complete in overlapping time periods. It doesn't necessarily mean they'll ever both be running at the same instant. Eg. multitasking on a single-core machine.
As an example, the danger of non-atomic operations is that one thread might read the value, another might modify the value, and then the original thread might modify and write the value (thus negating the modification the second thread did).
Atomic operations do not allow other operations access to the state while in the middle of the atomic operation. If, for example, the increment operator were atomic, it would read, modify, and write without any other thread having access to that variables state while those operations took place.
You can use AtomicInteger. The linked Javadoc says (in part) that it is an int value that may be updated atomically. AtomicInteger also implements addAndGet(int) which atomically adds the given value to the current value
private AtomicInteger ai = new AtomicInteger(1); // <-- or another initial value
public int increment() {
return ai.addAndGet(1); // <-- or another increment value
}
That can (for example) allow you to guarantee write order consistency for multiple threads. Consider, ai might represent (or include) some static (or global) resource. If a value is thread local then you don't need to consider atomicity.

When to use volatile and synchronized

I know there are many questions about this, but I still don't quite understand. I know what both of these keywords do, but I can't determine which to use in certain scenarios. Here are a couple of examples that I'm trying to determine which is the best to use.
Example 1:
import java.net.ServerSocket;
public class Something extends Thread {
private ServerSocket serverSocket;
public void run() {
while (true) {
if (serverSocket.isClosed()) {
...
} else { //Should this block use synchronized (serverSocket)?
//Do stuff with serverSocket
}
}
}
public ServerSocket getServerSocket() {
return serverSocket;
}
}
public class SomethingElse {
Something something = new Something();
public void doSomething() {
something.getServerSocket().close();
}
}
Example 2:
public class Server {
private int port;//Should it be volatile or the threads accessing it use synchronized (server)?
//getPort() and setPort(int) are accessed from multiple threads
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
Any help is greatly appreciated.
A simple answer is as follows:
synchronized can always be used to give you a thread-safe / correct solution,
volatile will probably be faster, but can only be used to give you a thread-safe / correct in limited situations.
If in doubt, use synchronized. Correctness is more important than performance.
Characterizing the situations under which volatile can be used safely involves determining whether each update operation can be performed as a single atomic update to a single volatile variable. If the operation involves accessing other (non-final) state or updating more than one shared variable, it cannot be done safely with just volatile. You also need to remember that:
updates to non-volatile long or a double may not be atomic, and
Java operators like ++ and += are not atomic.
Terminology: an operation is "atomic" if the operation either happens entirely, or it does not happen at all. The term "indivisible" is a synonym.
When we talk about atomicity, we usually mean atomicity from the perspective of an outside observer; e.g. a different thread to the one that is performing the operation. For instance, ++ is not atomic from the perspective of another thread, because that thread may be able to observe state of the field being incremented in the middle of the operation. Indeed, if the field is a long or a double, it may even be possible to observe a state that is neither the initial state or the final state!
The synchronized keyword
synchronized indicates that a variable will be shared among several threads. It's used to ensure consistency by "locking" access to the variable, so that one thread can't modify it while another is using it.
Classic Example: updating a global variable that indicates the current time
The incrementSeconds() function must be able to complete uninterrupted because, as it runs, it creates temporary inconsistencies in the value of the global variable time. Without synchronization, another function might see a time of "12:60:00" or, at the comment marked with >>>, it would see "11:00:00" when the time is really "12:00:00" because the hours haven't incremented yet.
void incrementSeconds() {
if (++time.seconds > 59) { // time might be 1:00:60
time.seconds = 0; // time is invalid here: minutes are wrong
if (++time.minutes > 59) { // time might be 1:60:00
time.minutes = 0; // >>> time is invalid here: hours are wrong
if (++time.hours > 23) { // time might be 24:00:00
time.hours = 0;
}
}
}
The volatile keyword
volatile simply tells the compiler not to make assumptions about the constant-ness of a variable, because it may change when the compiler wouldn't normally expect it. For example, the software in a digital thermostat might have a variable that indicates the temperature, and whose value is updated directly by the hardware. It may change in places that a normal variable wouldn't.
If degreesCelsius is not declared to be volatile, the compiler is free to optimize this:
void controlHeater() {
while ((degreesCelsius * 9.0/5.0 + 32) < COMFY_TEMP_IN_FAHRENHEIT) {
setHeater(ON);
sleep(10);
}
}
into this:
void controlHeater() {
float tempInFahrenheit = degreesCelsius * 9.0/5.0 + 32;
while (tempInFahrenheit < COMFY_TEMP_IN_FAHRENHEIT) {
setHeater(ON);
sleep(10);
}
}
By declaring degreesCelsius to be volatile, you're telling the compiler that it has to check its value each time it runs through the loop.
Summary
In short, synchronized lets you control access to a variable, so you can guarantee that updates are atomic (that is, a set of changes will be applied as a unit; no other thread can access the variable when it's half-updated). You can use it to ensure consistency of your data. On the other hand, volatile is an admission that the contents of a variable are beyond your control, so the code must assume it can change at any time.
There is insufficient information in your post to determine what is going on, which is why all the advice you are getting is general information about volatile and synchronized.
So, here's my general advice:
During the cycle of writing-compiling-running a program, there are two optimization points:
at compile time, when the compiler might try to reorder instructions or optimize data caching.
at runtime, when the CPU has its own optimizations, like caching and out-of-order execution.
All this means that instructions will most likely not execute in the order that you wrote them, regardless if this order must be maintained in order to ensure program correctness in a multithreaded environment. A classic example you will often find in the literature is this:
class ThreadTask implements Runnable {
private boolean stop = false;
private boolean work;
public void run() {
while(!stop) {
work = !work; // simulate some work
}
}
public void stopWork() {
stop = true; // signal thread to stop
}
public static void main(String[] args) {
ThreadTask task = new ThreadTask();
Thread t = new Thread(task);
t.start();
Thread.sleep(1000);
task.stopWork();
t.join();
}
}
Depending on compiler optimizations and CPU architecture, the above code may never terminate on a multi-processor system. This is because the value of stop will be cached in a register of the CPU running thread t, such that the thread will never again read the value from main memory, even thought the main thread has updated it in the meantime.
To combat this kind of situation, memory fences were introduced. These are special instructions that do not allow regular instructions before the fence to be reordered with instructions after the fence. One such mechanism is the volatile keyword. Variables marked volatile are not optimized by the compiler/CPU and will always be written/read directly to/from main memory. In short, volatile ensures visibility of a variable's value across CPU cores.
Visibility is important, but should not be confused with atomicity. Two threads incrementing the same shared variable may produce inconsistent results even though the variable is declared volatile. This is due to the fact that on some systems the increment is actually translated into a sequence of assembler instructions that can be interrupted at any point. For such cases, critical sections such as the synchronized keyword need to be used. This means that only a single thread can access the code enclosed in the synchronized block. Other common uses of critical sections are atomic updates to a shared collection, when usually iterating over a collection while another thread is adding/removing items will cause an exception to be thrown.
Finally two interesting points:
synchronized and a few other constructs such as Thread.join will introduce memory fences implicitly. Hence, incrementing a variable inside a synchronized block does not require the variable to also be volatile, assuming that's the only place it's being read/written.
For simple updates such as value swap, increment, decrement, you can use non-blocking atomic methods like the ones found in AtomicInteger, AtomicLong, etc. These are much faster than synchronized because they do not trigger a context switch in case the lock is already taken by another thread. They also introduce memory fences when used.
Note: In your first example, the field serverSocket is actually never initialized in the code you show.
Regarding synchronization, it depends on whether or not the ServerSocket class is thread safe. (I assume it is, but I have never used it.) If it is, you don't need to synchronize around it.
In the second example, int variables can be atomically updated so volatile may suffice.
volatile solves “visibility” problem across CPU cores. Therefore, value from local registers is flushed and synced with RAM. However, if we need consistent value and atomic op, we need a mechanism to defend the critical data. That can be achieved by either synchronized block or explicit lock.

Categories