Why is this code thread safe? - java

I am preparing for the OCP exam and I found this question in a mock exam:
Given:
class Calculator {
private AtomicInteger i = new AtomicInteger();
public void add(int value) {
int oldValue = i.get();
int newValue = oldValue + value;
System.out.print(i.compareAndSet(oldValue,newValue));
}
public int getValue() {
return i.get();
}
}
What could you do to make this class thread safe?
And surprisingly, to me, the answer is:
"Class Calculator is thread-safe"
It must be that I have not understood correctly the concept. To my understanding, a class is thread safe when all the methods work as expected under thread concurrency. Now, if two thread call at the same time getValue(), then call add() passing a different value, and then they call getValue() again, the 'second' thread won't see its value passed increased.
I understand that the oldValue and the newValue as local variables are stored in the method stack, but that doesn't prevent that the second call to compareAndSet will find that the oldValue is not the current value and so won't add the newValue.
What am I missing here?

According to JCIP
A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or
interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or
other coordination on the part of the calling code.
Although there is no definition of thread-safety and no specification of the class, in my opinion, by any sane definition of an add method in a Calculator class it is "correct" if it the value of the AtomicInteger i is increased in any case, "regardless of the scheduling or interleaving of the execution".
Therefore, in my opinion, the class is not thread-safe by this definition.

There is clearly a problem with the term "thread-safe" here, in that it isn't absolute. What is considered thread-safe depends on what you expect the program to do. And in most real-world applications you wouldn't consider this code thread-safe.
However the JLS formally specifies a different concept:
A program is correctly synchronized if and only if all sequentially
consistent executions are free of data races.
If a program is correctly synchronized, then all executions of the
program will appear to be sequentially consistent
Correctly synchronized is a precisely defined, objective condition and according to that definition the code is correctly synchronized because every access to i is in a happens-before relationship with every other access, and that's enough to satisfy the criteria.
The fact that the exact order of reads/writes depends on unpredictable timing is a different problem, outside the realms of correct synchronization (but well within what most people would call thread safety).

The add method is going to do one of two things:
Add value to the value of i, and print true.
Do nothing and print false.
The theoretically sound1 definitions of thread-safe that I have seen say something like this:
Given a set of requirements, a program is thread-safe with respect to those requirements if it correct with respect to those requirements for all possible executions in a multi-threaded environment.
In this case, we don't have a clear statement of requirements, but if we infer that the intended behavior is as above, then that class is thread-safe with respect to the inferred requirements.
Now if the requirements were that add always added value to i, then that implementation does not meet the requirement. In that case, you could argue that the method is not thread-safe. (In a single-threaded use-case add would always work, but in a multi-threaded use-case the add method could occasionally fail to meet the requirement ... and hence would be non-thread-safe.)
1 - By contrast, the Wikipedia description (seen on 2016-01-17) is this: "A piece of code is thread-safe if it only manipulates shared data structures in a manner that guarantees safe execution by multiple threads at the same time." The problem is that it doesn't say what "safe execution" means. Eric Lippert's 2009 blog post "What is this thing you call thread-safe" is really pertinent.

It's threadsafe because compareAndSet is threadsafe and that's the only part that's modifying shared resources in the object.
It doesn't make a difference how many threads enter that method body at the same time. The first one to reach the end and call compareAndSet "wins" and gets to change the value while the others find the value has changed on them and compareAndSet returns false. It never results in the system being in an indeterminate state, though callers would probably have to handle the false outcome in any realistic scenario.

Related

Explain how JIT reordering works

I have been reading a lot about synchronization in Java and all the problems that can occur. However, what I'm still slightly confused about is how the JIT can reorder a write.
For instance, a simple double check lock makes sense to me:
class Foo {
private volatile Helper helper = null; // 1
public Helper getHelper() { // 2
if (helper == null) { // 3
synchronized(this) { // 4
if (helper == null) // 5
helper = new Helper(); // 6
}
}
return helper;
}
}
We use volatile on line 1 to enforce a happens-before relationship. Without it, is entirely possible for the JIT to reoder our code. For example:
Thread 1 is at line 6 and memory is allocated to helper however, the constructor has not yet run because the JIT could reordering our code.
Thread 2 comes in at line 2 and gets an object that is not fully created yet.
I understand this, but I don't fully understand the limitations that the JIT has on reordering.
For instance, say I have a method that creates and puts a MyObject into a HashMap<String, MyObject> (I know that a HashMapis not thread safe and should not be used in a multi-thread environment, but bear with me). Thread 1 calls createNewObject:
public class MyObject {
private Double value = null;
public MyObject(Double value) {
this.value = value;
}
}
Map<String, MyObject> map = new HashMap<String, MyObject>();
public void createNewObject(String key, Double val){
map.put(key, new MyObject( val ));
}
At the same time thread 2 calls a get from the Map.
public MyObject getObject(String key){
return map.get(key);
}
Is it possible for thread 2 to receive an object from getObject(String key) that is not fully constructed? Something like:
Thread 1: Allocate memory for new MyObject( val )
Thread 1: Place object in map
Thread 2: call getObject(String key)
Thread 1: Finish constructing the new MyObject.
Or will map.put(key, new MyObject( val )) not put an object into the map until it's fully constructed?
I'd imagine that the answer is, it wouldn't put an object into the Map until it is fully constructed (because that sounds awful). So how can the JIT reorder?
In a nutshell can it only reorder when creating a new Object and assigning it to a reference variable, like the double checked lock? A complete rundown on the JIT might be much for a SO answer, but what I'm really curious about is how it can reorder a write (like line 6 on the double checked lock) and what stops it from putting an object into a Map that is not fully constructed.
WARNING: WALL OF TEXT
The answer to your question is before the horizontal line. I will continue to explain deeper the fundamental problem in the second portion of my answer (which is not related to the JIT, so that's it if you are only interested in the JIT). The answer to the second part of your question lies at the bottom because it relies on what I describe further.
TL;DR The JIT will do whatever it wants, the JMM will do whatever it wants, being valid under the condition that you let them by writing thread unsafe code.
NOTE: "initialization" refers to what happens in the constructor, which excludes anything else such as calling a static init method after constructing etc...
"If the reordering produces results consistent with a legal execution, it is not illegal." (JLS 17.4.5-200)
If the result of a set of actions conforms to a valid chain of execution as per the JMM, then the result is allowed regardless of whether the author intended the code to produce that result or not.
"The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model.
This provides a great deal of freedom for the implementor to perform a myriad of code transformations, including the reordering of actions and removal of unnecessary synchronization" (JLS 17.4).
The JIT will reorder whatever it sees fit unless we do not allow it using the JMM (in a multithreaded environment).
The details of what the JIT can or will do is nondeterministic. Looking at millions of samples of runs will not produce a meaningful pattern because reorderings are subjective, they depend on very specific details such as CPU arch, timings, heuristics, graph size, JVM vendor, bytecode size, etc... We only know that the JIT will assume that the code runs in a single threaded environment when it does not need to conform to the JMM. In the end, the JIT matters very little to your multithreaded code. If you want to dig deeper, see this SO answer and do a little research on such topics as IR Graphs, the JDK HotSpot source, and compiler articles such as this one. But again, remember that the JIT has very little to do with your multithreaded code transforms.
In practice, the "object that is not fully created yet" is not a side effect of the JIT but rather the memory model (JMM). In summary, the JMM is a specification that puts forth guarantees of what can and cannot be results of a certain set of actions, where actions are operations that involve a shared state. The JMM is more easily understood by higher level concepts such as atomicity, memory visibility, and ordering, those three of which are components of a thread-safe program.
To demonstrate this, it is highly unlikely for your first sample of code (the DCL pattern) to be modified by the JIT that would produce "an object that is not fully created yet." In fact, I believe that it is not possible to do this because it would not follow the order or execution of a single-threaded program.
So what exactly is the problem here?
The problem is that if the actions aren't ordered by a synchronization order, a happens-before order, etc... (described again by JLS 17.4-17.5) then threads are not guaranteed to see the side effects of performing such actions. Threads might not flush their caches to update the field, threads might observe the write out of order. Specific to this example, threads are allowed to see the object in an inconsistent state because it is not properly published. I'm sure that you have heard of safe publishing before if you have ever worked even the tiniest bit with multithreading.
You might ask, well if single-threaded execution cannot be modified by the JIT, why can the multithreaded version be?
Put simply, it's because the thread is allowed to think ("perceive" as usually written in textbooks) that the initialization is out of order due to the lack of proper synchronization.
"If Helper is an immutable object, such that all of the fields of Helper are final, then double-checked locking will work without having to use volatile fields. The idea is that a reference to an immutable object (such as a String or an Integer) should behave in much the same way as an int or float; reading and writing references to immutable objects are atomic" (The "Double-Checked Locking is Broken" Declaration).
Making the object immutable ensures that the state is fully initialized when the constructor exits.
Remember that object construction is always unsynchronized. An object that is being initialized is ONLY visible and safe with respect to the thread that constructed it. In order for other threads to see the initialization, you must publish it safely. Here are those ways:
"There are a few trivial ways to achieve safe publication:
Exchange the reference through a properly locked field (JLS 17.4.5)
Use static initializer to do the initializing stores (JLS 12.4)
Exchange the reference via a volatile field (JLS 17.4.5), or as the consequence of this rule, via the AtomicX classes
Initialize the value into a final field (JLS 17.5)."
(Safe Publication and Safe Initialization in Java)
Safe publication ensures that other threads will be able to see the fully initialized objects when after it finishes.
Revisiting our idea that threads are only guaranteed to see side effects if they are in order, the reason that you need volatile is so that your write to the helper in thread 1 is ordered with respect to the read in thread 2. Thread 2 is not allowed to perceive the initialization after the read because it occurs before the write to helper. It piggy backs on the volatile write such that the read must happen after the initialization AND THEN the write to the volatile field (transitive property).
To conclude, an initialization will only occur after the object is created only because another thread THINKS that is the order. An initialization will never occur after construction due to a JIT optimisation. You can fix this by ensuring proper publication through a volatile field or by making your helper immutable.
Now that I've described the general concepts behind how publication works in the JMM, hopefully understanding how your second example won't work will be easy.
I'd imagine that the answer is, it wouldn't put an object into the Map until it is fully constructed (because that sounds awful). So how can the JIT reorder?
To the constructing thread, it will put it into the map after initialization.
To the reader thread, it can see whatever the hell it wants. (improperly constructed object in HashMap? That is definitely within the realm of possibility).
What you described with your 4 steps is completely legal. There is no order between assigning value or adding it to the map, thus thread 2 can perceive the initialization out of order since MyObject was published unsafely.
You can actually fix this problem by just converting to ConcurrentHashMap and getObject() will be completely thread safe as once you put the object in the map, the initialization will occur before the put and both will need to occur before the get as a result of ConcurrentHashMap being thread safe. However, once you modify the object, it will become a management nightmare because you need to ensure that updating the state is visible and atomic - what if a thread retrieves an object and another thread updates the object before the first thread could finish modifying and putting it back in the map?
T1 -> get() MyObject=30 ------> +1 --------------> put(MyObject=31)
T2 -------> get() MyObject=30 -------> +1 -------> put(MyObject=31)
Alternatively you could also make MyObject immutable, but you still need to map the map ConcurrentHashMap in order for other threads to see the put - thread caching behavior might cache an old copy and not flush and keep reusing the old version. ConcurrentHashMap ensures that its writes are visible to readers and ensures thread-safety. Recalling our 3 prerequisites for thread-safety, we get visibility from using a thread-safe data structure, atomicity by using an immutable object, and finally ordering by piggybacking on ConcurrentHashMap's thread safety.
To wrap up this entire answer, I will say that multithreading is a very difficult profession to master, one that I myself most definitely have not. By understanding concepts of what makes a program thread-safe and thinking about what the JMM allows and guarantees, you can ensure that your code will do what you want it to do. Bugs in multithreaded code occur often as a result of the JMM allowing a counterintuitive result that is within its parameters, not the JIT doing performance optimisations. Hopefully you will have learned something a little bit more about multithreading if you read everything. Thread safety should be achieved by building a repertoire of thread-safe paradigms rather than using little inconveniences of the spec (Lea or Bloch, not even sure who said this).

Interpretation of "program order rule" in Java concurrency

Program order rule states "Each action in a thread happens-before every action in that thread that comes later in the program order"
1.I read in another thread that an action is
reads and writes to variables
locks and unlocks of monitors
starting and joining with threads
Does this mean that reads and writes can be changed in order, but reads and writes cannot change order with actions specified in 2nd or 3rd lines?
2.What does "program order" mean?
Explanation with an examples would be really helpful.
Additional related question
Suppose I have the following code:
long tick = System.nanoTime(); //Line1: Note the time
//Block1: some code whose time I wish to measure goes here
long tock = System.nanoTime(); //Line2: Note the time
Firstly, it's a single threaded application to keep things simple. Compiler notices that it needs to check the time twice and also notices a block of code that has no dependency with surrounding time-noting lines, so it sees a potential to reorganize the code, which could result in Block1 not being surrounded by the timing calls during actual execution (for instance, consider this order Line1->Line2->Block1). But, I as a programmer can see the dependency between Line1,2 and Block1. Line1 should immediately precede Block1, Block1 takes a finite amount of time to complete, and immediately succeeded by Line2.
So my question is: Am I measuring the block correctly?
If yes, what is preventing the compiler from rearranging the order.
If no, (which is think is correct after going through Enno's answer) what can I do to prevent it.
P.S.: I stole this code from another question I asked in SO recently.
It probably helps to explain why such rule exist in the first place.
Java is a procedural language. I.e. you tell Java how to do something for you. If Java executes your instructions not in the order you wrote, it would obviously not work. E.g. in the below example, if Java would do 2 -> 1 -> 3 then the stew would be ruined.
1. Take lid off
2. Pour salt in
3. Cook for 3 hours
So, why does the rule not simply say "Java executes what you wrote in the order you wrote"? In a nutshell, because Java is clever. Take the following example:
1. Take eggs out of the freezer
2. Take lid off
3. Take milk out of the freezer
4. Pour egg and milk in
5. Cook for 3 hours
If Java was like me, it'll just execute it in order. However Java is clever enough to understand that it's more efficient AND that the end result would be the same should it do 1 -> 3 -> 2 -> 4 -> 5 (you don't have to walk to the freezer again, and that doesn't change the recipe).
So what the rule "Each action in a thread happens-before every action in that thread that comes later in the program order" is trying to say is, "In a single thread, your program will run as if it was executed in the exact order you wrote it. We might change the ordering behind the scene but we make sure that none of that would change the output.
So far so good. Why does it not do the same across multiple threads? In multi-thread programming, Java isn't clever enough to do it automatically. It will for some operations (e.g. joining threads, starting threads, when a lock (monitor) is used etc.) but for other stuff you need to explicitly tell it to not do reordering that would change the program output (e.g. volatile marker on fields, use of locks etc.).
Note:
Quick addendum about "happens-before relationship". This is a fancy way of saying no matter what reordering Java might do, stuff A will happen before stuff B. In our weird later stew example, "Step 1 & 3 happens-before step 4 "Pour egg and milk in" ". Also for example, "Step 1 & 3 do not need a happens-before relationship because they don't depend on each other in any way"
On the additional question & response to the comment
First, let us establish what "time" means in the programming world. In programming, we have the notion of "absolute time" (what's the time in the world now?) and the notion of "relative time" (how much time has passed since x?). In an ideal world, time is time but unless we have an atomic clock built in, the absolute time would have to be corrected time to time. On the other hand, for relative time we don't want corrections as we are only interested in the differences between events.
In Java, System.currentTime() deals with absolute time and System.nanoTime() deals with relative time. This is why the Javadoc of nanoTime states, "This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time".
In practice, both currentTimeMillis and nanoTime are native calls and thus the compiler can't practically prove if a reordering won't affect the correctness, which means it will not reorder the execution.
But let us imagine we want to write a compiler implementation that actually looks into native code and reorders everything as long as it's legal. When we look at the JLS, all that it tells us is that "You can reorder anything as long as it cannot be detected". Now as the compiler writer, we have to decide if the reordering would violate the semantics. For relative time (nanoTime), it would clearly be useless (i.e. violates the semantics) if we'd reorder the execution. Now, would it violate the semantics if we'd reorder for absolute time (currentTimeMillis)? As long as we can limit the difference from the source of the world's time (let's say the system clock) to whatever we decide (like "50ms")*, I say no. For the below example:
long tick = System.currentTimeMillis();
result = compute();
long tock = System.currentTimeMillis();
print(result + ":" + tick - tock);
If the compiler can prove that compute() takes less than whatever maximum divergence from the system clock we can permit, then it would be legal to reorder this as follows:
long tick = System.currentTimeMillis();
long tock = System.currentTimeMillis();
result = compute();
print(result + ":" + tick - tock);
Since doing that won't violate the spec we defined, and thus won't violate the semantics.
You also asked why this is not included in the JLS. I think the answer would be "to keep the JLS short". But I don't know much about this realm so you might want to ask a separate question for that.
*: In actual implementations, this difference is platform dependent.
The program order rule guarantees that, within individual threads, reordering optimizations introduced by the compiler cannot produce different results from what would have happened if the program had been executed in serial fashion. It makes no guarantees about what order the thread's actions may appear to occur in to any other threads if its state is observed by those threads without synchronization.
Note that this rule speaks only to the ultimate results of the program, and not to the order of individual executions within that program. For instance, if we have a method which makes the following changes to some local variables:
x = 1;
z = z + 1;
y = 1;
The compiler remains free to reorder these operations however it sees best fit to improve performance. One way to think of this is: if you could reorder these ops in your source code and still obtain the same results, the compiler is free to do the same. (And in fact, it can go even further and completely discard operations which are shown to have no results, such as invocations of empty methods.)
With your second bullet point the monitor lock rule comes into play: "An unlock on a monitor happens-before every subsequent lock on that main monitor lock." (Java Concurrency in Practice p. 341) This means that a thread acquiring a given lock will have a consistent view of the actions which occurred in other threads before releasing that lock. However, note that this guarantee only applies when two different threads release or acquire the same lock. If Thread A does a bunch of stuff before releasing Lock X, and then Thread B acquires Lock Y, Thread B is not assured to have a consistent view of A's pre-X actions.
It is possible for reads and writes to variables to be reordered with start and join if a.) doing so doesn't break within-thread program order, and b.) the variables have not had other "happens-before" thread synchronization semantics applied to them, say by storing them in volatile fields.
A simple example:
class ThreadStarter {
Object a = null;
Object b = null;
Thread thread;
ThreadStarter(Thread threadToStart) {
this.thread = threadToStart;
}
public void aMethod() {
a = new BeforeStartObject();
b = new BeforeStartObject();
thread.start();
a = new AfterStartObject();
b = new AfterStartObject();
a.doSomeStuff();
b.doSomeStuff();
}
}
Since the fields a and b and the method aMethod() are not synchronized in any way, and the action of starting thread does not change the results of the writes to the fields (or the doing of stuff with those fields), the compiler is free to reorder thread.start() to anywhere in the method. The only thing it could not do with the order of aMethod() would be to move the order of writing one of the BeforeStartObjects to a field after writing an AfterStartObject to that field, or to move one of the doSomeStuff() invocations on a field before the AfterStartObject is written to it. (That is, assuming that such reordering would change the results of the doSomeStuff() invocation in some way.)
The critical thing to bear in mind here is that, in the absence of synchronization, the thread started in aMethod() could theoretically observe either or both of the fields a and b in any of the states which they take on during the execution of aMethod() (including null).
Additional question answer
The assignments to tick and tock cannot be reordered with respect to the code in Block1 if they are to be actually used in any measurements, for example by calculating the difference between them and printing the result as output. Such reordering would clearly break Java's within-thread as-if-serial semantics. It changes the results from what would have been obtained by executing instructions in the specified program order. If the assignments aren't used for any measurements and have no side-effects of any kind on the program result, they'll likely be optimized away as no-ops by the compiler rather than being reordered.
Before I answer the question,
reads and writes to variables
Should be
volatile reads and volatile writes (of the same field)
Program order doesn't guarantee this happens before relationship, rather the happens-before relationship guarantees program order
To your questions:
Does this mean that reads and writes can be changed in order, but reads and writes cannot change order with actions specified in 2nd or 3rd lines?
The answer actually depends on what action happens first and what action happens second. Take a look at the JSR 133 Cookbook for Compiler Writers. There is a Can Reorder grid that lists the allowed compiler reordering that can occur.
For instance a Volatile Store can be re-ordered above or below a Normal Store but a Volatile Store cannot be be reordered above or below a Volatile Load. This is all assuming intrathread semantics still hold.
What does "program order" mean?
This is from the JLS
Among all the inter-thread actions performed by each thread t, the
program order of t is a total order that reflects the order in which
these actions would be performed according to the intra-thread
semantics of t.
In other words, if you can change the writes and loads of a variable in such a way that it will preform exactly the same way as you wrote it then it maintains program order.
For instance
public static Object getInstance(){
if(instance == null){
instance = new Object();
}
return instance;
}
Can be reordered to
public static Object getInstance(){
Object temp = instance;
if(instance == null){
temp = instance = new Object();
}
return temp;
}
it simply mean though the thread may be multiplxed, but the internal order of the thread's action/operation/instruction would remain constant (relatively)
thread1: T1op1, T1op2, T1op3...
thread2: T2op1, T2op2, T2op3...
though the order of operation (Tn'op'M) among thread may vary, but operations T1op1, T1op2, T1op3 within a thread will always be in this order, and so as the T2op1, T2op2, T2op3
for ex:
T2op1, T1op1, T1op2, T2op2, T2op3, T1op3
Java tutorial http://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html says that happens-before relationship is simply a guarantee that memory writes by one specific statement are visible to another specific statement. Here is an illustration
int x;
synchronized void x() {
x += 1;
}
synchronized void y() {
System.out.println(x);
}
synchronized creates a happens-before relationship, if we remove it there will be no guarantee that after thread A increments x thread B will print 1, it may print 0

Is my class threadsafe? If not why?

Is my class threadsafe? If not why?
class Foo {
boolean b = false;
void doSomething() throws Exception {
while (b) Thread.sleep();
}
void setB(boolean b) {
this.b = b;
}
}
The code is not thread safe because a running thread may see changes until the code is compiled (which could be at a random point later) and you no longer see changes.
BTW: This makes testing it very hard to do. e.g. if you sleep for 1 second you might not see this behaviour for almost three hours.
i.e. it may or may not work and you cannot say just because it has worked it will continue to work.
As b is not volatile the JIT can and will optimise
while (b) Thread.sleep(N);
to be
boolean b = this.b;
if (b) while (true) Thread.sleep(N);
so the value of b is not read each time.
It is not. setB() updating instance variable b value but is not synchronized.
Multiple threads may try to execute setB() method at same point of time may result in un-predicted results.
You need to synchronize the method (or) use synchronize block with lock on this object.
Take a look at AtomicBoolean. This will mean that only one thread can access it at any one time.
But, how is it relates to thread safety? little confused.
It goes back to the definition of "thread-safe". Wikipedia says this:
"Thread safety is a computer programming concept applicable in the context of multi-threaded programs. A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads."
The key point here is functions correctly. If you look at the scenario explained by Peter Lawrey, you can see that JIT compilation can result in code that doesn't notice when the value of b changes from true to false, and instead loops for ever. This is clearly incorrect behaviour. And since this only manifests when there are two threads, it is a thread-safety issue.
An at-issue concept here is visibility, discussed in Concurrent Java. If doSomething() is running on a different thread, the JVM makes no guarantee that the action taken in setB will apply to the version of b that doSomething sees. So you could call setB and doSomething is not guaranteed to ever terminate.

What is the name of this locking technique?

I've got a gigantic Trove map and a method that I need to call very often from multiple threads. Most of the time this method shall return true. The threads are doing heavy number crunching and I noticed that there was some contention due to the following method (it's just an example, my actual code is bit different):
synchronized boolean containsSpecial() {
return troveMap.contains(key);
}
Note that it's an "append only" map: once a key is added, is stays in there forever (which is important for what comes next I think).
I noticed that by changing the above to:
boolean containsSpecial() {
if ( troveMap.contains(key) ) {
// most of the time (>90%) we shall pass here, dodging lock-acquisition
return true;
}
synchronized (this) {
return troveMap.contains(key);
}
}
I get a 20% speedup on my number crunching (verified on lots of runs, running during long times etc.).
Does this optimization look correct (knowing that once a key is there it shall stay there forever)?
What is the name for this technique?
EDIT
The code that updates the map is called way less often than the containsSpecial() method and looks like this (I've synchronized the entire method):
synchronized void addSpecialKeyValue( key, value ) {
....
}
This code is not correct.
Trove doesn't handle concurrent use itself; it's like java.util.HashMap in that regard. So, like HashMap, even seemingly innocent, read-only methods like containsKey() could throw a runtime exception or, worse, enter an infinite loop if another thread modifies the map concurrently. I don't know the internals of Trove, but with HashMap, rehashing when the load factor is exceeded, or removing entries can cause failures in other threads that are only reading.
If the operation takes a significant amount of time compared to lock management, using a read-write lock to eliminate the serialization bottleneck will improve performance greatly. In the class documentation for ReentrantReadWriteLock, there are "Sample usages"; you can use the second example, for RWDictionary, as a guide.
In this case, the map operations may be so fast that the locking overhead dominates. If that's the case, you'll need to profile on the target system to see whether a synchronized block or a read-write lock is faster.
Either way, the important point is that you can't safely remove all synchronization, or you'll have consistency and visibility problems.
It's called wrong locking ;-) Actually, it is some variant of the double-checked locking approach. And the original version of that approach is just plain wrong in Java.
Java threads are allowed to keep private copies of variables in their local memory (think: core-local cache of a multi-core machine). Any Java implementation is allowed to never write changes back into the global memory unless some synchronization happens.
So, it is very well possible that one of your threads has a local memory in which troveMap.contains(key) evaluates to true. Therefore, it never synchronizes and it never gets the updated memory.
Additionally, what happens when contains() sees a inconsistent memory of the troveMap data structure?
Lookup the Java memory model for the details. Or have a look at this book: Java Concurrency in Practice.
This looks unsafe to me. Specifically, the unsynchronized calls will be able to see partial updates, either due to memory visibility (a previous put not getting fully published, since you haven't told the JMM it needs to be) or due to a plain old race. Imagine if TroveMap.contains has some internal variable that it assumes won't change during the course of contains. This code lets that invariant break.
Regarding the memory visibility, the problem with that isn't false negatives (you use the synchronized double-check for that), but that trove's invariants may be violated. For instance, if they have a counter, and they require that counter == someInternalArray.length at all times, the lack of synchronization may be violating that.
My first thought was to make troveMap's reference volatile, and to re-write the reference every time you add to the map:
synchronized (this) {
troveMap.put(key, value);
troveMap = troveMap;
}
That way, you're setting up a memory barrier such that anyone who reads the troveMap will be guaranteed to see everything that had happened to it before its most recent assignment -- that is, its latest state. This solves the memory issues, but it doesn't solve the race conditions.
Depending on how quickly your data changes, maybe a Bloom filter could help? Or some other structure that's more optimized for certain fast paths?
Under the conditions you describe, it's easy to imagine a map implementation for which you can get false negatives by failing to synchronize. The only way I can imagine obtaining false positives is an implementation in which key insertions are non-atomic and a partial key insertion happens to look like another key you are testing for.
You don't say what kind of map you have implemented, but the stock map implementations store keys by assigning references. According to the Java Language Specification:
Writes to and reads of references are always atomic, regardless of whether they are implemented as 32 or 64 bit values.
If your map implementation uses object references as keys, then I don't see how you can get in trouble.
EDIT
The above was written in ignorance of Trove itself. After a little research, I found the following post by Rob Eden (one of the developers of Trove) on whether Trove maps are concurrent:
Trove does not modify the internal structure on retrievals. However, this is an implementation detail not a guarantee so I can't say that it won't change in future versions.
So it seems like this approach will work for now but may not be safe at all in a future version. It may be best to use one of Trove's synchronized map classes, despite the penalty.
I think you would be better off with a ConcurrentHashMap which doesn't need explicit locking and allows concurrent reads
boolean containsSpecial() {
return troveMap.contains(key);
}
void addSpecialKeyValue( key, value ) {
troveMap.putIfAbsent(key,value);
}
another option is using a ReadWriteLock which allows concurrent reads but no concurrent writes
ReadWriteLock rwlock = new ReentrantReadWriteLock();
boolean containsSpecial() {
rwlock.readLock().lock();
try{
return troveMap.contains(key);
}finally{
rwlock.readLock().release();
}
}
void addSpecialKeyValue( key, value ) {
rwlock.writeLock().lock();
try{
//...
troveMap.put(key,value);
}finally{
rwlock.writeLock().release();
}
}
Why you reinvent the wheel?
Simply use ConcurrentHashMap.putIfAbsent

visibility of immutable object after publication

I have an immutable object, which is capsulated in class and is global state.
Lets say i have 2 threads that get this state, execute myMethod(state) with it. And lets say thread1 finish first. It modify the global state calling GlobalStateCache.updateState(state, newArgs);
GlobalStateCache {
MyImmutableState state = MyImmutableState.newInstance(null, null);
public void updateState(State currentState, Args newArgs){
state = MyImmutableState.newInstance(currentState, newArgs);
}
}
So thread1 will update the cached state, then thread2 do the same, and it will override the state (not take in mind the state updated from thread1)
I searched google, java specifications and read java concurrency in practice but this is clearly not specified.
My main question is will the immutable state object value be visible to a thread which already had read the immutable state. I think it will not see the changed state, only reads after the update will see it.
So i can not understand when to use immutable objects? Is this depends on if i am ok with concurrent modifications during i work with the latest state i have saw and not need to update the state?
Publication seems to be somewhat tricky concept, and the way it's explained in java concurrency in practice didn't work well to me (as opposed to many other multithreading concepts explained in this wonderful book).
With above in mind, let's first get clear on some simpler parts of your question.
when you state lets say thread1 finish first - how would you know that? or, to be more precise, how would thread2 "know" that? as far as I can tell this could be only possible with some sort of synchronization, explicit or not-so-explicit like in thread join (see the JLS - 17.4.5 Happens-before Order). Code you provided so far does not give sufficient details to tell whether this is the case or not
when you state that thread1 will update the cached state - how would thread2 "know" that? with the piece of code you provided, it looks entirely possible (but not guaranteed mind you) for thread2 to never know about this update
when you state thread2... will override the state what does override mean here? There's nothing in GlobalStateCache code example that could somehow guarantee that thread1 will ever notice this override. Even more, the code provided suggests nothing that would somehow impose happen-before relation of updates from different threads so one can even speculate that override may happen the other way around, you see?
the last but not the least, the wording the immutable state sounds rather fuzzy to me. I would say dangerously fuzzy given this tricky subject. The field state is mutable, it can be changed, well, by invoking method updateState right? From your code I would rather conclude that instances of MyImmutableState class are assumed to be immutable - at least that's what name tells me.
With all above said, what is guaranteed to be visible with the code you provided so far? Not much I'm afraid... but maybe better than nothing at all. The way I see it is...
For thread1, it is guaranteed that prior to invoking updateState it will see either null or properly constructed (valid) object updated from thread2. After the update, it is guaranteed to see either of properly constructed (valid) objects updated from thread1 or thread2. Note after this update thread1 is guaranteed not to see null per the very JLS 17.4.5 I refer to above ("...x and y are actions of the same thread and x comes before y in program order...")
For thread2, guarantees are pretty similar to above.
Essentially, all that is guaranteed with the code you provided is that both threads will see either null or one of properly constructed (valid) instances of MyImmutableState class.
Above guarantees may look insignificant at the first glance, but if you skim one page above the one with quote that confused you ("Immutable objects can be used safely etc..."), you'll find an example worth deeper drilling into in 3.5.1. Improper Publication: When Good Objects Go Bad.
Yeah object being immutable alone won't guarantee its visibility but it at least will guarantee that the object won't "explode from inside", like in example provided in 3.5.1:
public class Holder {
private int n;
public Holder(int n) { this.n = n; }
public void assertSanity() {
if (n != n)
throw new AssertionError("This statement is false.");
}
}
Goetz comments for above code begin at explaining issues true for both mutable and immutable objects, ...we say the Holder was not properly published. Two things can go wrong with improperly published objects. Other threads could see a stale value for the holder field, and thus see a null reference or other older value even though a value has been placed in holder...
...then he dives into what can happen if object is mutable, ...But far worse, other threads could see an up-todate value for the holder reference, but stale values for the state of the Holder. To make things even less predictable, a thread may see a stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertSanity can throw AssertionError.
Above "AssertionHorror" may sound counter-intuitive but all the magic goes away if you consider scenario like below (completely legal per Java 5 memory model - and for a good reason btw):
thread1 invokes sharedHolderReference = Holder(42);
thread1 first fills n field with default value (0) then is going to assign it within constructor but...
...but scheduler switches to thread2,
sharedHolderReference from thread1 becomes visible to thread2 because, say because why not? maybe optimizing hot-spot compiler decided it's a good time for that
thread2 reads the up-todate sharedHolderReference with field value still being 0 btw
thread2 invokes sharedHolderReference.assertSanity()
thread2 reads the left side value of if statement within assertSanity which is, well, 0 then it is going to read the right side value but...
...but scheduler switches back to thread1,
thread1 completes the constructor assignment suspended at step #2 above by setting n field value 42
value 42 in the field n from thread1 becomes visible to thread2 because, say because why not? maybe optimizing hot-spot compiler decided it's a good time for that
then, at some moment later, scheduler switches back to thread2
thread2 proceeds from where it was suspended at step #6 above, ie it reads right-hand side of if statement, which is, well, 42 now
oops our innocent if (n != n) suddenly turns into if (0 != 42) which...
...naturally throws AssertionError
As far as I understand, initialization safety for immutable objects just guarantees that above won't happen - no more... and no less
I think the key is to distinguish between objects and references.
The immutable objects are safe to publish, so any thread can publish object, and if any other thread reads a reference to such object - it can safely use the object. Of course, reader thread will see the immutable object state that was published at the moment the thread read the reference, it will not see any updates, until it reads the reference again.
It is very useful in many situations. E.g. if there is a single publisher, and many readers - and readers need to see a consistent state. The readers periodically read the reference, and work on the obtained state - it is guaranteed to be consistent, and it does not require any locking on reader thread. Also when it is OK to loose some updates, e.g. you don't care which thread updates the state.
If I understand your question, immutability doesn't seem to be relevant here. You're just asking whether threads will see updates to shared objects.
[Edit] after an exchange of comments, I now see that you need also to hold a reference to your shared singleton state while doing some actions, and then setting the state to reflect that action.
The good news, as before, is that providing this will of necessity also solve your memory consistency issue.
Instead of defining separate synchronized getState and updateState methods, you'll have to perform all three actions without being interrupted: getState, yourAction, and updateState.
I can see three ways to do it:
1) Do all three steps inside a single synchronized method in GlobalStateCache. Define an atomic doActionAndUpdateState method in GlobalStateCache, synchronized of course on your state singleton, which would take a functor object to do your action.
2) Do getState and updateState as separate calls, and change updateState so that it checks to be sure state hasn't changed since the get. Define getState and checkAndUpdateState in GlobalStateCache. checkAndUpdateState will take the original state caller got from getState, and must be able to check if state has changed since your get. If it has changed, you'll need to do something to let caller know they potentially need to revert their action (depends on your use case).
3) Define a getStateWithLock method in GlobalStateCache. This implies that you'll also need to assure callers release their lock. I'd create an explicit releaseStateLock method, and have your updateState method call it.
Of these, I advise against #3, because it leaves you vulnerable to leaving that state locked in the event of some kinds of bugs. I'd also advise (though less strongly) against #2, because of the complexity it creates with what happens in the event that the state has changed: do you just abandon the action? Do you retry it? Must it be (can it be) reverted? I'm for #1: a single synchronized atomic method, which will look something like this:
public interface DimitarActionFunctor {
public void performAction();
}
GlobalStateCache {
private MyImmutableState state = MyImmutableState.newInstance(null, null);
public MyImmutableState getState {
synchronized(state) {
return state;
}
}
public void doActionAndUpdateState(DimitarActionFunctor functor, State currentState, Args newArgs){
synchronized(state) {
functor.performAction();
state = MyImmutableState.newInstance(currentState, newArgs);
}
}
}
}
Caller then constructs a functor for the action (an instance of DimitarActionFunctor), and calls doActionAndUpdateState. Of course, if the actions need data, you'll have to define your functor interface to take that data as arguments.
Again, I point you to this question, not for the actual difference, but for how they both work in terms of memory consistency: Difference between volatile and synchronized in Java
So much depends on the actual use case here that it's hard to make a recommendation, but it looks like you want some sort of Compare-And-Set semantics for the GlobalStateCache, using a java.util.concurrent.atomic.AtomicReference.
public class GlobalStateCache {
AtomicReference<MyImmutableState> atomic = new AtomicReference<MyImmutableState>(MyImmutableState.newInstance(null, null);
public State getState()
{
return atomic.get();
}
public void updateState( State currentState, Args newArgs )
{
State s = currentState;
while ( !atomic.compareAndSet( s, MyImmutableState.newInstance( s, newArgs ) ) )
{
s = atomic.get();
}
}
}
This, of course, depends on the expense of potentially creating a few extra MyImmutableState objects, and whether you need to re-run myMethod(state) if the state has been updated underneath, but the concept should be correct.
Answering you "main" question: no Thread2 will not see the change. Immutable objects do not change :-)
So if Thread1 read state A and then Thread2 stores state B, Thread1 should read the variable again to see the changes.
Visibily of variables is affected by volatile keyword. If variable is declared as volatile then Java guarantees that if one thread updates the variable all other threads will see the change immediately (at the cost of speed).
Still immutable objects are very useful in multithreaded environments. I will give you an example how I used it once. Lets say you have an object that is periodically changed (life field in my case) by one thread and it is somehow processed by other threads (my program was sending it to clients over the network). These threads fail if the object is changed in the middle of processing (they send inconsistent life field state). If you make this object immutable and will create a new instance every time it changes, you don't have to write any synchronization at all. Updating thread will periodically publish new versions of an object and every time other threads read it they will have most recent version of it and can safely process it. This particular example saves time spent on synchronization but wastes more memory. This should give you a general understanding when you can use them.
Another link I found: http://download.oracle.com/javase/tutorial/essential/concurrency/immutable.html
Edit (answer comment):
I will explain my task. I had to write a network server that will send clients the most recent life field and will constantly update it. With design mentioned above, I have two types of threads:
Thread that updates object that represents life field. It is immutable, so actually it creates a new instance every time and only changes reference. The fact that reference is declared volatile is crucial.
Every client is served with its own thread. When client requests life field, it reads the reference once and starts sending. Because network connection can be slow, life field can be updated many times while this thread sends data. The fact that object is immutable guarantees that server will send consistent state of life field. In the comments you are concerned about changes made while this thread processes the object. Yes, when client receives data it may not be up to date but there is nothing you can do about it. This is not synchronization issue but rather a slow connection issue.
I am not stating that immutable objects can solve all of your concurrency problems. This is obviously not true and you point this out. I am trying to explain you where it actually can solve problems. I hope my example is clear now.

Categories

Resources