Java double checked locking code explanation - java

I have a code snippet that I don't understand I will highlight the bit that confused me.
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance; // <---------- This bit, why do we assign it here ?
if (r == null) {
synchronized (lock) { // What is the benefit of this lock in here
r = instance; // assuming instance is null which will pass the first if ( r == null, what do we assign it again ?? I don't get the idea of this step at all.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
I have seen https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples but there implementation looks like this, which doesn't have two assignments.
public static ThreadSafeSingleton getInstanceUsingDoubleLocking(){
if(instance == null){
synchronized (ThreadSafeSingleton.class) {
if(instance == null){
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}

YourObject r = instance; // <---------- This bit, why do we assign it here ?
It is easier to reason about local variables, which you really want here. Also there is overhead in reading volatile variables that may not be merged by the optimiser.
synchronized (lock) { // What is the benefit of this lock in here
This is the lock that prevents multiple threads creating and assigning different instances of YourObject simultaneously.
r = instance; // assuming instance is null which will pass the first if ( r == null, what do we assign it again ?? I don't get the idea of this step at all.
instance may have changed between the first read for the null check and the lock being successfully acquired.
Anyway, don't use double-checked locking - it's very confusing and there's probably better ways.

Related

Double checked locking with neither volatile nor a local variable

Before dismissing this, it is possible to implement double checked locking without volatile, see below. I'm suggesting a variation on this, that gets rid of the local variable.
The following is a correct implementation of double checked locking from Shipilev:
public class FinalWrapperFactory {
private FinalWrapper wrapper;
public Singleton get() {
FinalWrapper w = wrapper;
if (w == null) { // check 1
synchronized(this) {
w = wrapper;
if (w == null) { // check2
w = new FinalWrapper(new Singleton());
wrapper = w;
}
}
}
return w.instance;
}
private static class FinalWrapper {
public final Singleton instance;
public FinalWrapper(Singleton instance) {
this.instance = instance;
}
}
}
I wonder if it would be possible to get rid of the local variable w:
public class FinalWrapperFactory {
private FinalWrapper wrapper; //same as example above
public Singleton get() {
if (wrapper == null) { // read 1
synchronized(this) {
if (wrapper == null) { // read 2
wrapper = new FinalWrapper(new Singleton());
return wrapper.instance; // read 3
} else {
return wrapper.instance; // read 4
}
}
} else {
return wrapper.instance; // read 5 (last read). Can this be reordered?
}
}
}
In 17.4.8. Executions and Causality Requirements of the JLS 8 it is written:
Informally, we allow an action to be committed early if we know that
the action can occur without assuming some data race occurs.
The big question here is if the last read (read 5) can be reordered so that we could potentially see a non-null wrapper in read 1 and still see a null in the last read. This should not be allowed to happen in the first invocation of get() by a thread because then the only way for the last read to occur would be because of a data race and the JMM would prohibit the reordering.
In subsequent invocations of get() reordering would be allowed but then it shouldn't matter because wrapper should be visible anyways.

Atomic compareAndSet but with callback?

I know that AtomicReference has compareAndSet, but I feel like what I want to do is this
private final AtomicReference<Boolean> initialized = new AtomicReference<>( false );
...
atomicRef.compareSetAndDo( false, true, () -> {
// stuff that only happens if false
});
this would probably work too, might be better.
atomicRef.compareAndSet( false, () -> {
// stuff that only happens if false
// if I die still false.
return true;
});
I've noticed there's some new functional constructs but I'm not sure if any of them are what I'm looking for.
Can any of the new constructs do this? if so please provide an example.
update
To attempt to simplify my problem, I'm trying to find a less error prone way to guard code in a "do once for object" or (really) lazy initializer fashion, and I know that some developers on my team find compareAndSet confusing.
guard code in a "do once for object"
how exactly to implement that depends on what you want other threads attempting to execute the same thing in the meantime. if you just let them run past the CAS they may observe things in an intermediate state while the one thread that succeeded does its action.
or (really) lazy initializer fashion
that construct is not thread-safe if you're using it for lazy initializers because the "is initialized" boolean may be set to true by one thread and then execute the block while another thread observes the true-state but reads an empty result.
You can use Atomicreference::updateAndGet if multiple concurrent/repeated initialization attempts are acceptable with one object winning in the end and the others being discarded by GC. The update method should be side-effect-free.
Otherwise you should just use the double checked locking pattern with a variable reference field.
Of course you can always package any of these into a higher order function that returns a Runnable or Supplier which you then assign to a final field.
// == FunctionalUtils.java
/** #param mayRunMultipleTimes must be side-effect-free */
public static <T> Supplier<T> instantiateOne(Supplier<T> mayRunMultipleTimes) {
AtomicReference<T> ref = new AtomicReference<>(null);
return () -> {
T val = ref.get(); // fast-path if already initialized
if(val != null)
return val;
return ref.updateAndGet(v -> v == null ? mayRunMultipleTimes.get() : v)
};
}
// == ClassWithLazyField.java
private final Supplier<Foo> lazyInstanceVal = FunctionalUtils.instantiateOne(() -> new Foo());
public Foo getFoo() {
lazyInstanceVal.get();
}
You can easily encapsulate various custom control-flow and locking patterns this way. Here are two of my own..
compareAndSet returns true if the update was done, and false if the actual value was not equal to the expected value.
So just use
if (ref.compareAndSet(expectedValue, newValue)) {
...
}
That said, I don't really understand your examples, since you're passing true and false to a method taking object references as argument. And your second example doesn't do the same thing as the first one. If the second is what you want, I think what you're after is
ref.getAndUpdate(value -> {
if (value.equals(expectedValue)) {
return someNewValue(value);
}
else {
return value;
}
});
You’re over-complicating things. Just because there are now lambda expression, you don’t need to solve everything with lambdas:
private volatile boolean initialized;
…
if(!initialized) synchronized(this) {
if(!initialized) {
// stuff to be done exactly once
initialized=true;
}
}
The double checked locking might not have a good reputation, but for non-static properties, there are little alternatives.
If you consider multiple threads accessing it concurrently in the uninitialized state and want a guaranty that the action runs only once, and that it has completed, before dependent code is executed, an Atomic… object won’t help you.
There’s only one thread that can successfully perform compareAndSet(false,true), but since failure implies that the flag already has the new value, i.e. is initialized, all other threads will proceed as if the “stuff to be done exactly once” has been done while it might still be running. The alternative would be reading the flag first and conditionally perform the stuff and compareAndSet afterwards, but that allows multiple concurrent executions of “stuff”. This is also what happens with updateAndGet or accumulateAndGet and it’s provided function.
To guaranty exactly one execution before proceeding, threads must get blocked, if the “stuff” is currently executed. The code above does this. Note that once the “stuff” has been done, there will be no locking anymore and the performance characteristics of the volatile read are the same as for the Atomic… read.
The only solution which is simpler in programming, is to use a ConcurrentMap:
private final ConcurrentHashMap<String,Boolean> initialized=new ConcurrentHashMap<>();
…
initialized.computeIfAbsent("dummy", ignore -> {
// stuff to do exactly once
return true;
});
It might look a bit oversized, but it provides exactly the required performance characteristics. It will guard the initial computation using synchronized (or well, an implementation dependent exclusion mechanism) but perform a single read with volatile semantics on subsequent queries.
If you want a more lightweight solution, you may stay with the double checked locking shown at the beginning of this answer…
I know this is old, but I've found there is no perfect way to achieve this, more specifically this:
trying to find a less error prone way to guard code in a "do (anything) once..."
I'll add to this "while respecting a happens before behavior." which is required for instantiating singletons in your case.
IMO The best way to achieve this is by means of a synchronized function:
public<T> T transaction(Function<NonSyncObject, T> transaction) {
synchronized (lock) {
return transaction.apply(nonSyncObject);
}
}
This allows to preform atomic "transactions" on the given object.
Other options are double-check spin-locks:
for (;;) {
T t = atomicT.get();
T newT = new T();
if (atomicT.compareAndSet(t, newT)) return;
}
On this one new T(); will get executed repeatedly until the value is set successfully, so it is not really a "do something once".
This would only work on copy on write transactions, and could help on "instantiating objects once" (which in reality is instantiating many but at the end is referencing the same) by tweaking the code.
The final option is a worst performant version of the first one, but this one is a true happens before AND ONCE (as opposed to the double-check spin-lock):
public void doSomething(Runnable r) {
while (!atomicBoolean.compareAndSet(false, true)) {}
// Do some heavy stuff ONCE
r.run();
atomicBoolean.set(false);
}
The reason why the first one is the better option is that it is doing what this one does, but in a more optimized way.
As a side note, in my projects I've actually used the code below (similar to #the8472's answer), that at the time I thought safe, and it may be:
public T get() {
T res = ref.get();
if (res == null) {
res = builder.get();
if (ref.compareAndSet(null, res))
return res;
else
return ref.get();
} else {
return res;
}
}
The thing about this code is that, as the copy on write loop, this one generates multiple instances, one for each contending thread, but only one is cached, the first one, all the other constructions eventually get GC'd.
Looking at the putIfAbsent method I see the benefit is the skipping of 17 lines of code and then a synchronized body:
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
And then the synchronized body itself is another 34 lines:
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
The pro(s) of using a ConcurrentHashMap is that it will undoubtedly work.

Design Singleton Pattern - Constructor

I am unable to create an object using singleton design pattern, here is what I did:
class Test {
public static Test objTest = null;
public static int count = 0;
public static Test CreateObject() {
if (objTest != null)
objTest = new Test();
return objTest;
}
private Test() {
Test.count++;
}
}
Have I created zeroton pattern ?
Check your if condition inside createObject method once. it should be if(objTest == null) .
Besides the fact, that your count would always be either '0' or '1' (ignoring potential multi-threading issues) - why do you have that parameter?
You are checking for objTest != null instead of objTest == null.
That's why you are always returning null and never create a new instance.
The objTest variable should also be private, you'll not want to reference to a null instance. Access to the instance should only be possible through your CreateObject() method.

Swap 2 values in 2 different AtomicReferences

I tried to implement a swap method for 2 AtomicReferences.
public void swap(AtomicReference<Object> a, AtomicReference<Object> b) {
while (true) {
Object value1 = a.get();
Object value2 = b.get();
if (a.compareAndSet(value1, value2) && b.compareAndSet(value2, value1)) return;
}
}
In my opinion, this solution is not correct. If multiple threads use this method at the same time, it could lead to the following scenario:
T1: ...get(); get(); compareAndSet() == true //-> BREAK (scheduler)
T2: ...get(); get(); compareAndSet() == true; compareAndSet() == true; return;
This would mean, T1 had set the value of a but will fail by setting the value of b. T1 would repeat the process EVEN if AtomicReference a has been set.
Does someone of you have a better idea, how to implement something like this? It would be easy, if you would just have one AtomicReference. Maybe it isn't possible using 2 AtomicReference's and I should consider using one AtomicReference that points to an Object[].
In Scala, this method is super easy to implement, since you have atomic blocks.
class Swappy[A](_a: A, _b: A) {
#volatile
var a = Ref(_a)
#volatile
var b = Ref(_b)
def swap(): Unit = {
atomic {
implicit tx =>
val tmp = a
a = b
b = tmp
}
}
def elems: (A, A) = (a.single(), b.single())
}
I created a solution with a different approach. This should be 100% thread safe. I switched to using just one AtomicReference. If anyone could find a better way, feel free to write an answer. :)
package test;
import java.util.concurrent.atomic.*;
public class ScalaSTMPendant {
AtomicReference<Object[]> a;
public ScalaSTMPendant(Object a, Object b) {
this.a = new AtomicReference<>(new Object[] {a,b});
}
public void swap() {
while (true) {
Object[] origin = a.get();
Object[] swapped = new Object[] {origin[1], origin[0]};
if (a.compareAndSet(origin, swapped)) return;
}
}
public Object[] elems() {
Object[] temp = a.get();
return new Object[] {temp[0], temp[1]};
}
}
Would an Exchanger help? I'm not sure who is swapping what, but an Exchanger would help you do a swap atomically.
Also, the scala sample above uses ScalaSTM. You could do the same in Java using another STM implementation (or even ScalaSTM). For example: Multiverse.

Create and put a map value only if not already present, and get it: thread-safe implementation

What is the best way to make this snippet thread-safe?
private static final Map<A, B> MAP = new HashMap<A, B>();
public static B putIfNeededAndGet(A key) {
B value = MAP.get(key);
if (value == null) {
value = buildB(...);
MAP.put(key, value);
}
return value;
}
private static B buildB(...) {
// business, can be quite long
}
Here are the few solutions I could think about:
I could use a ConcurrentHashMap, but if I well understood, it just makes the atomic put and get operations thread-safe, i.e. it does not ensure the buildB() method to be called only once for a given value.
I could use Collections.synchronizedMap(new HashMap<A, B>()), but I would have the same issue as the first point.
I could set the whole putIfNeededAndGet() method synchronized, but I can have really many threads accessing this method together, so it could be quite expensive.
I could use the double-checked locking pattern, but there is still the related out-of-order writes issue.
What other solutions may I have?
I know this is a quite common topic on the Web, but I didn't find a clear, full and working example yet.
Use ConcurrentHashMap and the lazy init pattern which you used
public static B putIfNeededAndGet(A key) {
B value = map.get(key);
if (value == null) {
value = buildB(...);
B oldValue = map.putIfAbsent(key, value);
if (oldValue != null) {
value = oldValue;
}
}
return value;
}
This might not be the answer you're looking for, but use the Guava CacheBuilder, it already does all that and more:
private static final LoadingCache<A, B> CACHE = CacheBuilder.newBuilder()
.maximumSize(100) // if necessary
.build(
new CacheLoader<A, B>() {
public B load(A key) {
return buildB(key);
}
});
You can also easily add timed expiration and other features as well.
This cache will ensure that load() (or in your case buildB) will not be called concurrently with the same key. If one thread is already building a B, then any other caller will just wait for that thread.
In the above solution it is possible that many threads will class processB(...) simultaneously hence all will calculate. But in my case i am using Future and a single thread only get the old value as null hence it will only compute the processB rest will wait on f.get().
private static final ConcurrentMap<A, Future<B>> map = new ConcurrentHashMap<A, Future<B>>();
public static B putIfNeededAndGet(A key) {
while (true) {
Future<V> f = map.get(key);
if (f == null) {
Callable<B> eval = new Callable<V>() {
public B call() throws InterruptedException {
return buildB(...);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = map.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
ft.run();
}
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
}
}
}
Thought maybe this will be useful for someone else as well, using java 8 lambdas I created this function which worked great for me:
private <T> T getOrCreate(Object key, Map<Object, T> map,
Function<Object, T> creationFunction) {
T value = map.get(key);
// if the doesn't exist yet - create and add it
if (value == null) {
value = creationFunction.apply(key);
map.put(label, metric);
}
return value;
}
then you can use it like this:
Object o = getOrCreate(key, map, s -> createSpecialObjectWithKey(key));
I created this for something specific but changed the context and code to a more general look, that is why my creationFunction has one parameter, it can also have no parameters...
also you can generify it more by changing Object to a generic type, if it's not clear let me know and I'll add another example.
UPDATE:
I just found out about Map.computeIfAbsent which basically does the same, gotta love java 8 :)

Categories

Resources