volatile synchronized combination for performance - java

When Synchronization is used there is a performance impact. Can volatile be used in combination with synchronized to reduce the performance overhead ? For example, instance of Counter will be shared among many threads and each thread can access Counter's public methods. In the below code volatile is used for getter and synchronized is used for setter
public class Counter
{
private volatile int count;
public Counter()
{
count = 0;
}
public int getCount()
{
return count;
}
public synchronized void increment()
{
++count;
}
}
Please let me know in which scenario this might break ?

Yes, you definitely can. In fact, if you look at the source code of AtomicInteger, it's essentially what they do. AtomicInteger.get simply returns value, which is a volatile int (link). The only real difference from what you've done and what they do is that they use a CAS for the increment instead of synchronization. On modern hardware, a CAS can eliminate any mutual exclusion; on older hardware, the JVM will put some sort of mutex around the increment.
Volatile reads are about as fast as non-volatile ones, so the reads will be quite fast.
Not only that, but volatile fields are guaranteed not to tear: see JLS 17.7, which specifies that volatile longs and doubles are not subject to word tearing. So your code would work with a long just as well as an int.
As Diego Frehner points out, you might not see the result of an increment if you get the value "right as" the increment happens -- you'll either see the before or the after. Of course, if get were synchronized you'd have exactly the same behavior from the read thread -- you'd either see the before-increment or post-increment value. So it's really the same either way. In other words, it doesn't make sense to say that you won't see the value as it's happening -- unless you meant word tearing, which (a) you won't get and (b) you would never want.

1. I have personally used this mechanism of volatile combined with synchronized.
2. You can alone use synchronized, and you will always get a consistent result, but using
only volatile alone will Not yield the same result always.
3. This is because volatile keyword is not a synchronization primitive. It merely prevents caching of the value on the thread, but it does not prevent two threads from modifying the same value and writing it back concurrently.
4. volatile give concurrent access to threads without lock, but then using synchronized will allow only one thread to get access to this and all the synchronized methods in the class.
5. And using both volatile and synchronized will do this....
volatile - will reflect the changed values to thread, and prevent caching,
synchronized - But using synchronized keyword, will make sure that only one thread gets the access to the synchronized methods of the class.

You will not always get the most actual count when calling getCount(). An AtomicInteger could be appropriate for you.

There wouldn't be a performance gain from using both. Volatile guarantees that the value of a variable will be consistent when reading/writing to the variable across threads executing in parallel by preventing caching. Synchronized, when applied to a method (as you do in your example), only allows a single thread to enter that method at a time and blocks others until execution is complete.

Related

Is it necessary to make a primitive instance variable volatile?

Just to experiment with multithreading concepts, I'm implementing my own version of AtomicInteger that uses pessimistic locking. It looks something like this:
public class ThreadSafeInt {
public int i; // Should this be volatile?
public ThreadSafeInt(int i) {
this.i = i;
}
public synchronized int get() {
return i;
}
public synchronized int getAndIncrement() {
return this.i++;
}
// other synchronized methods for incrementAndGet(), etc...
}
I wrote a test that takes an instance of ThreadSafeInt, gives it to hundreds of threads, and makes each of those threads call getAndIncrement 100,000 times. What I'm seeing is that all the increments happen correctly, with the value of the integer being exactly (number of threads) * (number of increments per thread), even though I'm not using volatile on the primitive instance variable i. I expected that if I did not make i volatile, then I would get lots of visibility problems where, for instance, thread 1 increments i from 0 to 1, but thread 2 still sees the value of 0 and also increments it to only 1, causing a final value that is less than the correct value.
I understand that visibility problems occur randomly and can depend on properties of my environment, so that my test can appear to work fine even though there is inherent potential for visibility problems. So I'm inclined to think the volatile keyword is still necessary.
But is this correct? Or is there some property of my code (maybe the fact that it's just a primitive variable, etc) which I can actually trust to obviate the need for the volatile keyword?
even though I'm not using volatile on the primitive instance variable i. I expected that if I did not make i volatile, then I would get lots of visibility problems
By making your getAndIncrement() and get() methods synchronized, all of the threads that are modifying i are properly locking it for both the updates and the retrieval of the value. The synchronized blocks make it unnecessary for i to be volatile because they also ensure memory synchronization.
That said, you should be using an AtomicInteger instead which wraps a volatile int field. AtomicInteger getAndIncrement() method updates the value without having to resort to a synchronized block which is much faster while still being thread-safe.
public final AtomicInteger i = new AtomicInteger();
...
// no need for synchronized here
public int get() {
return i.get();
}
// nor here
public int getAndIncrement() {
return i.getAndIncrement();
}
I would get lots of visibility problems where, for instance, thread 1 increments i from 0 to 1, but thread 2 still sees the value of 0 and also increments it to only 1, causing a final value that is less than the correct value.
If your get() method was not synchronized then your increment might be handled right but other threads would not see the value of i published correctly. But with both methods being synchronized this ensures memory synchronization on reads and writes. synchronized also does the locks so that you can do the i++. Again the AtomicInteger handles the memory synchronization and the increment race conditions much more efficiently.
More specifically, when a synchronized block is entered, it crosses a read memory barrier which is the same as reading from a volatile field. When a synchronized block is exited, it crosses a write memory barrier which is the same as writing to a volatile field. The difference with the synchronized blocks is that there is also locking to ensure only one person is locking a particular object at one time.

AtomicInteger and volatile [duplicate]

This question already has answers here:
What is the difference between atomic / volatile / synchronized?
(7 answers)
Closed 3 years ago.
I know volatile allows for visibility, AtomicInteger allows for atomicity.
So if I use a volatile AtomicInteger, does it mean I don't have to use any more synchronization mechanisms?
Eg.
class A {
private volatile AtomicInteger count;
void someMethod(){
// do something
if(count.get() < 10) {
count.incrementAndGet();
}
}
Is this threadsafe?
I believe that Atomic* actually gives both atomicity and volatility. So when you call (say) AtomicInteger.get(), you're guaranteed to get the latest value. This is documented in the java.util.concurrent.atomic package documentation:
The memory effects for accesses and updates of atomics generally follow the rules for volatiles, as stated in section 17.4 of The Java™ Language Specification.
get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.
lazySet has the memory effects of writing (assigning) a volatile variable except that it permits reorderings with subsequent (but not previous) memory actions that do not themselves impose reordering constraints with ordinary non-volatile writes. Among other usage contexts, > - lazySet may apply when nulling out, for the sake of garbage collection, a reference that is never accessed again.
weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides no guarantees with respect to previous or subsequent reads and writes of any variables other than the target of the weakCompareAndSet.
compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing volatile variables.
Now if you have
volatile AtomicInteger count;
the volatile part means that each thread will use the latest AtomicInteger reference, and the fact that it's an AtomicInteger means that you'll also see the latest value for that object.
It's not common (IME) to need this - because normally you wouldn't reassign count to refer to a different object. Instead, you'd have:
private final AtomicInteger count = new AtomicInteger();
At that point, the fact that it's a final variable means that all threads will be dealing with the same object - and the fact that it's an Atomic* object means they'll see the latest value within that object.
I'd say no, it's not thread-safe, if you define thread-safe as having the same result under single threaded mode and multithreaded mode. In single threaded mode, the count will never go greater than 10, but in multithreaded mode it can.
The issue is that get and incrementAndGet is atomic but an if is not. Keep in mind that a non-atomic operation can be paused at any time. For example:
count = 9 currently.
Thread A runs if(count.get() <10) and gets true and stopped there.
Thread B runs if(count.get() <10) and gets true too so it runs count.incrementAndGet() and finishes. Now count = 10.
Thread A resumes and runs count.incrementAndGet(), now count = 11 which will never happen in single threaded mode.
If you want to make it thread-safe without using synchronized which is slower, try this implementation instead:
class A{
final AtomicInteger count;
void someMethod(){
// do something
if(count.getAndIncrement() <10){
// safe now
} else count.getAndDecrement(); // rollback so this thread did nothing to count
}
To maintain the original semantics, and support multiple threads, you could do something like:
public class A {
private AtomicInteger count = new AtomicInteger(0);
public void someMethod() {
int i = count.get();
while (i < 10 && !count.compareAndSet(i, i + 1)) {
i = count.get();
}
}
}
This avoids any thread ever seeing count reach 10.
Answer is there in this code
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java
This is source code of AtomicInteger.
The value is Volatile.
So,AtomicInteger uses Volatile inside.
Your query can be answered in 2 parts, because there are 2 questions in your query :
1)
Referring to Oracle's tutorial documentation for Atomic variables :
https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html
The java.util.concurrent.atomic package defines classes that support atomic operations on single variables. All classes have get and set methods that work like reads and writes on volatile variables. That is, a set has a happens-before relationship with any subsequent get on the same variable. The atomic compareAndSet method also has these memory consistency features, as do the simple atomic arithmetic methods that apply to integer atomic variables.
So atomic integer does use volatile inside, as other answers here have mentioned. So there's no point in making your atomic integer volatile. You need to synchronize your method.
You should watch John Purcell's free video on Udemy , where he shows the failure of volatile keyword when multiple threads are trying to modify it. Simple and beautiful example.
https://www.udemy.com/course/java-multithreading/learn/lecture/108950#overview
If you change the volatile counter in John's example into an atomic variable, his code is guaranteed to succeed without using sunchronized keyword like he has done in his tutorial
2) Coming to your code :
Say thread 1 kicks into action and "someMethod" does a get and checks for size. It is possible that before getAndIncrement executes(say, by thread 1) , another thread (say thread 2)kicks in and increases the count to 10, and gets out; after which, your thread 1 will resume and increase count to 11. This is erroneous output. This is because your "someMethod" is not protected in anyway from synhronization problems.
I would still recommend you to watch john purcell's videos to see where volatile fails , so that you have a better understanding of the keyword volatile. Replace it with atomicinteger in his example and see the magic.

Java: How exactly do synchronized operations relate to volatility?

Sorry this is such a long question.
Ive been doing lots of research lately into multi-threading as I slowly implement it into a personal project. However, probably due to an abundance of slightly incorrect examples, the use of synchronized blocks and volatility in certain situations is still a bit unclear to me.
My core question is this: Are changes to references and primitives automatically volatile (that is, performed on the main memory and not a cache) when a thread is inside a synchronized block, or does the read also have to be synchronized for it to work properly?
If so What is the purpose of synchronizing a simple getter method? (see example 1 ) Also, are ALL changes sent to main memory as long as the thread has synchronized on anything? eg if it is sent off to do loads of work all over the place inside a very high level sync will every single change then made be to main memory, and nothing ever to cache, until its unlocked again?
If not Does the change have to be explicitly inside a synchronized block, or can java actually pick up on, for example, uses of the Lock object? (see example 3)
If either Does the synchronized object need to be related to the reference/primitive being changed in any way (eg the immediate object that contains it)? Can I write by syncing on one object and read with another if its otherwise safe? (see example 2)
(please note for the following examples that I know that synchronized methods and synchronized(this) are frowned upon and why, but discussion about that is beyond the scope of my question)
Example 1:
class Counter{
int count = 0;
public synchronized void increment(){
count++;
}
public int getCount(){
return count;
}
}
In this example, increment() needs to be synchronized since ++ is not an atomic operation. As such, two threads incremending at the same time may result in a overall increase of 1 to the count. The count primitive needs to be atomic (eg not long/double/reference), and it is so thats fine.
Does getCount() need to be synchronized here and why exactly? The explanation I have heard the most is that I will have no guarantee whether the count returned will be the pre- or post-increment. However, this seems like the explanation for something slightly different, thats found itself in the wrong place. I mean if I were to synchronize getCount(), then I still see no guarantee - its now down to not knowing the locking order, insead of not knowing whether the actual read happens to be before/after the actual write.
Example 2:
Is the following example threadsafe, if you assume that through trickery not shown here that none of these methods will never be called at the same time? Will count increment in an expected way if its done so using a random method each time, and then be read properly, or does the lock have to be the same object? (btw I fully realise how rediculous this example is but Im more interested in theory than practice)
class Counter{
private final Object lock1 = new Object();
private final Object lock2 = new Object();
private final Object lock3 = new Object();
int count = 0;
public void increment1(){
synchronized(lock1){
count++;
}
}
public void increment2(){
synchronized(lock2){
count++;
}
}
public int getCount(){
synchronized(lock3){
return count;
}
}
}
Example 3:
Is the happens-before relationship simply a java concept, or is it an actual thing built into the JVM? Even though I can guarantee a conceptual happens-before relationship for this next example, is java smart enough to pick it up if its a built in thing? I am assuming it is not, but is this example actually threadsafe? If its threadsafe, what about if getCount() did no locking?
class Counter{
private final Lock lock = new Lock();
int count = 0;
public void increment(){
lock.lock();
count++;
lock.unlock();
}
public int getCount(){
lock.lock();
int count = this.count;
lock.unlock();
return count;
}
}
Yes, the read has to be synchronized as well. This page says:
The results of a write by one thread are guaranteed to be visible to a
read by another thread only if the write operation happens-before the
read operation.
[...]
An unlock (synchronized block or method exit) of a monitor
happens-before every subsequent lock (synchronized block or method
entry) of that same monitor
The same page says:
Actions prior to "releasing" synchronizer methods such as Lock.unlock,
Semaphore.release, and CountDownLatch.countDown happen-before actions
subsequent to a successful "acquiring" method such as Lock.lock
So locks offer the same visibility guarantees as synchronized blocks.
Whether you use synchronized blocks or locks, the visibility is only guaranteed if the reader thread uses the same monitor or lock as the writer thread.
Your Example 1 is incorrect: the getter must be synchronized as well if you want to see the latest value of the count.
Your example 2 is incorrect because it uses different locks to guard the same count.
Your example 3 is OK. If the getter did not lock, you could see an older value of the count. The happens-before is something that is guaranteed by the JVM. The JVM has to respect the rules specified, by flushing caches to the main memory for example.
Try to view it in terms of two distinct, simple operations:
Locking (mutual exclusion),
Memory barrier (cache sync, instruction reordering barrier).
Entering a synchronized block entails both locking and memory barrier; leaving the synchronized block entails unlocking + memory barrier; reading/writing a volatile field entails memory barrier only. Thinking in these terms I think you can clarify for yourself all the question above.
As for Example 1, the reading thread will not have any kind of memory barrier. It's not just between seeing the value before/after read, it's about never observing any change to the var after a thread is started.
Example 2. is the most interesting issue you raise. You are indeed given no guarantees by the JLS in this case. In practice you won't be given any ordering guarantees (it's as if the locking aspect wasn't there at all), but you'll still have the benefit of the memory barriers so you will observe changes, unlike the first example. Basically, this is exactly the same as removing synchronized and tagging the int as volatile (apart from the runtime costs of acquiring locks).
Regarding Example 3, by "just a Java thing" I feel you have generics with erasure in mind, something that only the static code checking is aware of. This is not like that -- both locks and memory barriers are pure runtime artifacts. In fact, the compiler can't reason about them at all.

synchronization on single statement?

if I have a getter method that has only one statement like this
public class NumberClass{
int number;
public int getNumber() {
return number;
}
...
}
and multiple threads access this method, do I have to synchronize this method or it is not necessary since it has only one statement??
I have to synchronize this [get] method or it is not necessary since it has only one statement??
It has nothing to do with 1 or more statements. It depends on whether or not the value has been updated in another thread and if you want all of the threads to see a consistent value.
If the number field was updated in thread1, then thread2 may get either the original value or the new value depending on how the update was synchronized. To have the value published appropriately both the set and get methods need to synchronized.
If you are just trying to share an int value then marking the number field as being volatile would work or using an AtomicInteger to share the value between multiple threads reliably may be more appropriate.
private volatile int number;
or use:
private AtomicInteger number = new AtomicInteger();
Yes, it may be a good idea to synchronize that statement. The reason is that each thread is, according to spec, allowed to cache its own version of the variable. To se it demonstrated, have a look at this answer.
Other options are to
Make the variable volatile:
volatile int number;
or to use AtomicInteger from the java.util.concurrent package:
AtomicInteger number;
As a side-note: If number had been of type long, not even a read of the variable would have been atomic (one thread could rewrite the value of the variable in the middle of a read). See Chapter 17.7: Non-atomic Treatment of double and long of the Java Language Specification.
You need a memory barrier, or other threads are not guaranteed to see the "correct" value (meaning, any value that is explicitly assigned to number).
To fix this, declare number as a final or volatile member, or access it from a synchronized block.
The number of statements, contrary to some other answers, is a consideration. You do not need atomicity (because it's a single statement), so using synchronized is probably overkill. If the value changes, use volatile, and if it doesn't, use final. If you had multiple statements that needed to appear as acting atomically, synchronized would be the only option.

Is a volatile int in Java thread-safe?

Is a volatile int in Java thread-safe? That is, can it be safely read from and written to without locking?
Yes, you can read from it and write to it safely - but you can't do anything compound such as incrementing it safely, as that's a read/modify/write cycle. There's also the matter of how it interacts with access to other variables.
The precise nature of volatile is frankly confusing (see the memory model section of the JLS for more details) - I would personally generally use AtomicInteger instead, as a simpler way of making sure I get it right.
[...] as in being able to be safely read from and written to without locking?
Yes, a read will always result in the value of the last write, (and both reads and writes are atomic operations).
A volatile read / write introduces a so called happens-before relation in the execution.
From the Java Language Specification Chapter 17: Threads and Locks
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
In other words, when dealing with volatile variables you don't have to explicitly synchronize (introduce a happens-before relation) using synchronized keyword in order to ensure that the thread gets the latest value written to the variable.
As Jon Skeet points out though, the use of volatile variables are limited, and you should in general consider using classes from the java.util.concurrent package instead.
Access to volatile int in Java will be thread-safe. When I say access I mean the unit operation over it, like volatile_var = 10 or int temp = volatile_var (basically write/read with constant values). Volatile keyword in java ensures two things :
When reading you always get the value in main memory. Generally for optimization purposes JVM use registers or in more general terms local memory foe storing/access variables. So in multi-threaded environment each thread may see different copy of variable. But making it volatile makes sure that write to variable is flushed to main memory and read to it also happens from main memory and hence making sure that thread see at right copy of variable.
Access to the volatile is automatically synchronized. So JVM ensures an ordering while read/write to the variable.
However Jon Skeet mentions rightly that in non atomic operations (volatile_var = volatile + 1) different threads may get unexpected result.
1) If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use a synchronized in that case to guarantee that the reading and writing of the variable is atomic. Reading or writing a volatile variable does not block threads reading or writing. For this to happen you must use the synchronized keyword around critical sections.
2) As an alternative to a synchronized block you could also use one of the many atomic data types found in the java.util.concurrent package. For instance, the AtomicLong or AtomicReference or one of the others.
It's thread safe if you have one writer thread and multiple reader threads.
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Note : If helper is immutable then no need of volatile keyword.Here singleton will work properly.
In case of counter which is being incremented by multiple threads (reading writing operation) will not give correct answer. This condition is also illustrated by race condition.
public class Counter{
private volatile int i;
public int increment(){
i++;
}
}
NOTE : Here volatile will not help.
Not always.
It's not thread safe if multiple threads are writing and reading the variable. It's thread safe if you have one writer thread and multiple reader threads.
If you are looking for Thread safely, use AtomicXXX classes
A small toolkit of classes that support lock-free thread-safe programming on single variables.
In essence, the classes in this package extend the notion of volatile values, fields, and array elements to those that also provide an atomic conditional update operation of the form:
boolean compareAndSet(expectedValue, updateValue);
Refer to #teto answer in below post:
Volatile boolean vs AtomicBoolean
If a volatile is not dependent on any other volatile variable its thread safe for read operation. In case of write volatile does not guarantee thread safety.
Assume you have a variable i which is volatile and its value is dependent on another volatile variable say j. Now Thread-1 access variable j and increment it and is about to update it in main memory from CPU cache. In case the Thread-2 reads the
variable i before Thread-1 can actually update the j in main memory. The value of i will be as per the old value of j which would be incorrect. Its also called Dirty read.

Categories

Resources