Java : Synchronization of code - java

I have this piece of code below as shown .
Our Application runs on 5 web servers controlled by a Load Balancer ,all connecting to one Memcache instance .
I guess that this piece of synchrnozation works only for one Instance .
Please let me know how can i synchrnoze this piece of code when 5 web servers are trying to access the Memcache
public class Memcache {
private MemcachedClient memclient = null;
private static Memcache instance = null;
public static Memcache getInstance() {
if (instance == null) {
try {
synchronized (Memcache.class) {
instance = new Memcache();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return instance;
}
private Memcache() throws IOException {
MemcachedClientBuilder builder = new XMemcachedClientBuilder();
memclient = builder.build();
}
}

Why not initialize it like this?
private static Memcache instance = new Memcache();
Bare in mind that what you tried to achieve at the synchronization here is problematic,
As two threads might pass the (if (instance == null) (a context switch might be after that line)
So you can consider the double check pattern,
BUt at some version of java there is a problem with it.
At the link I provided , there is info about problem, and
in this link, you can read about Singleton with the volatile keyword.
I still would go for the option I suggested above.

You can use the lazily initialized ClassHolder pattern to implement synchronized access to a class. Because the Memcache is initialized with a static initializer, it doesn't need more synchronization constructs. The first call to getInstance() by any thread causes MemcacheHolder to be loaded and initialized and the Memcache instance to make itself available to the calling code.
public class MemcacheFactory{
private static class MemcacheHolder {
public static Memcache instance = new Memcache();
}
public static Memcache getInstance() {
return MemcacheFactory.MemcacheHolder.instance;
}
}

Related

Why this synchronisation is not working in given scenario?

package singleton;
public class SingletonClass {
private static SingletonClass singleton = null;
private SingletonClass() {
}
static boolean stopThread = true;
//approach 1 which fails in multithereaded env
/*public static SingletonClass getInstance(){
if(null == singleton){
try {
if(stopThread){
stopThread = false;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SingletonClass();
}
return singleton;
}*/
//approach 2 which works
//method is synchronized
/* public static synchronized SingletonClass getInstance(){
if(null == singleton){
try {
if(stopThread){
stopThread = false;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SingletonClass();
}
return singleton;
}*/
***//approach 3 which is failing but I don't understand why
//big block of code is synchronized
public static SingletonClass getInstance(){
if(null == singleton){
synchronized (SingletonClass.class){
try {
if(stopThread){
stopThread = false;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SingletonClass();
}
}
return singleton;
}***
//small block of code is synchronized, checked null again because even object instantiation is synchronised
//if we don't check null, it will create new object once again
//approach 4 which works
/* public static SingletonClass getInstance(){
if(null == singleton){
try {
if(stopThread){
System.out.println("in thread...");
stopThread = false;
//even if we interchange above 2 lines it makes whole lot of difference
//till the time it takes to print "in thread"
//2nd thread reaches there n enters if(stopThread) block because
//stopThread is still true because 1st thread spent time in writing that sentence and
//did not set stopThread = false by the time 2nd thread reached there
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (SingletonClass.class){
System.out.println("in this block");
if(null == singleton){
singleton = new SingletonClass();
}
}
}
return singleton;
}*/
}
---------------------------------------------------------
package singleton;
public class ThreadUsage implements Runnable {
#Override
public void run() {
SingletonClass singletonOne = SingletonClass.getInstance();
System.out.println(singletonOne.hashCode());
}
}
----------------------------------------------------------------
package singleton;
class ThreadUsageTest {
public static void main(String[] args) {
Runnable runnableOne = new ThreadUsage();
Runnable runnableTwo = new ThreadUsage();
new Thread(runnableOne).start();
new Thread(runnableTwo).start();
}
}
---------------------------------------------------------------------------
In approach 3, it's not giving same hashCode for 2 objects, I've kept both Thread.sleep as well as object instantiation under synchronised block so what I'm thinking is , 2nd thread should not even enter this block until 1st finishes, but it's still doing and creating 2nd object leading to diff hashCode. What am I mssing here? Could someone correct my understanding here ? If I check for null b4 object creation then it's working as expected but why would I need to check null again here because my entire code is under synchronised block?
if(null == singleton)
singleton = new SingletonClass();
Here's one way that code (approach 3) ends up creating and returning two (or more) separate objects for the singleton:
Thread A enters the function and sees null for singleton
Thread B enters the function and sees null for singleton
Thread A enters the synchronized block
Thread B waits because it can't enter the synchronized block
Thread A assigns to singleton
Thread A exits the synchronized block
Thread A returns one object
Thread B enters the synchronized block
Thread B assigns to singleton
Thread B returns a different object
E.g., there's a gap between the null check and entering the synchronized block that follows it.
To solve it, just make getInstance a synchronized method and remove the synchronized block inside it:
public static synchronized SingletonClass getInstance() {
if (instance == null) {
singleton = new SingletonClass();
}
return singleton;
}
Or if you really want to avoid synchronization on subsequent calls, on Java 5 or later (which hopefully you're using!), declare singleton volatile and check again within the synchronized block:
private static volatile SingletonClass singleton;
// ...
public static SingletonClass getInstance() { // Only works reliably on Java 5 (aka 1.5) and later!
SingletonClass instance = singleton;
if (instance == null) {
synchronized (SingletonClass.class) {
instance = singleton;
if (instance == null) {
singleton = instance = new SingletonClass();
}
}
}
return instance;
}
That's the double-checked locking idiom. In Java 4 (aka 1.4) and earlier that wasn't necessarily reliable, but it is now (provided you use volatile on the member).
In a comment user2683814 asked a good question:
Could you explain the assignment to local variable before null check in the second code snippet ? Checking the class variable directly won’t work ?
Yes, it would work, but less efficiently.
In cases where singleton is non-null, using a local means the method only accesses singleton once. If the code didn't use a local, it would access singleton at least twice (once to check it, once to return it). Since accessing a volatile variable is slightly expensive, better to use the local (which in the code above can be optimized into a register).
That may seem like premature micro-optimization, but if you weren't doing this in performance-critical code, you'd just make the method synchronized and avoid the complexity of double-checked locking entirely. :-)
In approach three, you do a check on the singleton variable; you do this outside of any synchronized block, which is why it doesn't work: There is no guarantee here that threads wait before checking. They all check as fast as they can, which is why 2+ threads may all see a null here, even as one of them is already at work making that instance.
You then synchronize, sure. However, that doesn't magically give this code 'only assign singleton once' powers - after all, the code in that singleton block IS going to assign a newly created instance of SingletonClass to the singleton variable.
Two relevant notes:
[1] The java memory model states that any given field is like schroedinger's cat: Each thread has a copy of it, or doesn't - up to the threading model. An individual copy is sent out to each other thread's copy, or to some of them, at arbitrary times, and the same goes for receiving updates from the others. You can't rely on this mechanism, it may not even be used, there is no way to control it (other than volatile which can help but it's a bit tricky to use correctly). The point is to write your code such that it can't matter. Once you establish 'comes before' / 'comes after' relationships between code, for example because you use a synchronized block, this arbitrary nature goes away, and you are guaranteed visibility (so if code A comes before code B, e.g. because they both synchronize on the same object and A 'won' the battle, anything A writes anywhere will be visible to B once B gets to run, guaranteed, because there is a CA/CB relationship here).
Put that null check inside and all of a sudden the problem goes away.
[2] If all you're trying to accomplish is that there is exactly one instance of SingletonClass, you're barking up the wrong tree. This is not how to do that. It is in fact TRIVIALLY simple. All you do, is this one line:
public class SingletonClass {
public static final SingletonClass instance = new SingletonClass();
private SingletonClass() {
// ensure nobody but you can call this.
}
}
That's it. You may think this means the class is initialized as your app boots, but that's not true. Classes are only loaded if some code is run that uses the class. Assuming ALL uses of SingletonClass involve getting that singleton instance (usually true), this is as good as anything. If for some bizarre reason code may interact with SC without grabbing the singleton, you can still use this mechanism, just, using an inner class:
public class SingletonClass {
private SingletonClass() {}
public static SingletonClass getInstance() {
return Inner.instance;
}
private static class Instance {
private static final SingletonClass instance = new SingletonClass();
}
}
This guaranteed does not call that constructor until someone calls getInstance(), only calls it once, CANNOT ever call it twice, and does it in the most efficient way possible.
EDIT: Formatting.
So problem was both threads can reach method at once and so both will get object as null at once before first one entering synchrosied block.
Using #rzwitserloot and #T.J. Crowder comments, I reached to conclusion that, it's not necessary to use synchronised for creating SIngleton object.
Below code can do that and it's been testing with thread tests n junits as well
package singleton;
public class SingletonClassSecond {
private static SingletonClassSecond singleton = new SingletonClassSecond();
private SingletonClassSecond() {
}
public static SingletonClassSecond getInstance(){
return singleton;
}
}
---------------------------------------------------------------------------
package singleton;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class SingletonClassTest {
#Test
public void shouldCreateSingleton(){
SingletonClass singletonOne = SingletonClass.getInstance();
SingletonClass singletonTwo = SingletonClass.getInstance();
singletonOne.print("1");
singletonTwo.print("2");
Assertions.assertEquals(singletonOne.hashCode(),singletonTwo.hashCode());
}
}
--------------------------------------------------------------------------------
package singleton;
class ThreadUsageTest {
public static void main(String[] args) {
Runnable runnable = new ThreadUsageSecond();
Runnable runnableTwo = new ThreadUsageSecond();
Runnable runnableThree = new ThreadUsageSecond();
Runnable runnableFour = new ThreadUsageSecond();
new Thread(runnable).start();
new Thread(runnableTwo).start();
new Thread(runnableThree).start();
new Thread(runnableFour).start();
}
}
Hashcode is same for all 4 threads.

Sonar Violation: Dodgy - Write to static field from instance method

I have a variable - "protected static Context jndi;" in my class where "Context" is an interface . When i try to access it in the below mentioned method, it generates the sonar violation mentioned in the title
public JMSQueueResource createQueueResource(String queueBindingName, String qcfBindingName, boolean messagePersisted, boolean autoAcknowledge, boolean nonJMS) throws JMSException, NamingException {
JMSQueueResource qResource = new JMSQueueResource();
try {
jndi = createInitialContext();
if (queueConnectionFactory == null) {
queueConnectionFactory = (QueueConnectionFactory) lookup(jndi, qcfBindingName);
}
qResource.theQueueConnection = queueConnectionFactory.createQueueConnection();
if (autoAcknowledge) {
qResource.theQueueSession = qResource.theQueueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
}
else {
qResource.theQueueSession = qResource.theQueueConnection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
}
Queue queue = (Queue) lookup(jndi, queueBindingName);
//if (nonJMS && queue instanceof com.ibm.mq.jms.MQQueue) {
// com.ibm.mq.jms.MQQueue q = (com.ibm.mq.jms.MQQueue) queue;
// q.setTargetClient(JMSC.MQJMS_CLIENT_NONJMS_MQ);
//}
qResource.theQueueSender = qResource.theQueueSession.createSender(queue);
if (messagePersisted) {
qResource.theQueueSender.setDeliveryMode(DeliveryMode.PERSISTENT);
}
else {
qResource.theQueueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
qResource.theQueueConnection.start();
}
catch (JMSException jmse) {
throw jmse;
}
catch (NamingException ne) {
throw ne;
}
finally {
if(jndi != null){
jndi.close();
}
}
return qResource;
}
I could see there are suggestions like to use an Atomic Integer wrapper. What is the best fix for this problem?
The sonar violation is a valid one as mutating a static variable from an instance method can lead to some pretty messed up behavior like:
How can you ensure that the field is initialized by an instance method before a static read access?
What happens when multiple threads access the field, directly or through the createQueueResource method?
Regarding the Java documentation, making it static and potentially accessed by multiple thread is a bad idea:
An InitialContext instance is not synchronized against concurrent
access by multiple threads. Multiple threads each manipulating a
different InitialContext instance need not synchronize. Threads that
need to access a single InitialContext instance concurrently should
synchronize amongst themselves and provide the necessary locking.
Having a local variable as suggested seems like a reasonable first way to avoid the warning and the related problems.
Whether the construction of the context is expensive depends also on the factory that is used to provide it.
First you need to worry about the correctness of the program, then you can optimize when you can test where the real bottlenecks are.
EDIT:
This link should provide more insight into the Spring application context and how to leverage the dependency injection of the Spring container to make use of the Context instead of storing it in a variable in a class https://spring.io/understanding/application-context

Behavior of singletons in task queues on app-engine

What happens to my static variables when app-engine spins new instances? More specifically I am using a Task Queue that can have 40 instances/thread. Within the Servlet in question, I am using a singleton, as in
public class WorkerThread extends HttpServlet {
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
..
MySingleton single = MySingleton.getInstance();
..
}
...
}
Here is how the singleton is created
public class MySingleton {
public static I MySingleton getInstance() {
return MySingletonHolder.INSTANCE;
}
private static class MySingletonHolder {
public static final MySingleton INSTANCE = new MySingleton();
}
private MySingleton() {
}
..
}
I have the following questions:
Since this is a Task Queue, do I have to worry about App-Engine starting new instances to scale with high demands?
Does it matter if the singleton is an inner class of the WorkerThread class or another class that the WorkerThread class is accessing?
Are Task Queues instance independent? A believe they are but am not sure.
I hope the question is clear. I want there to be only one instance of my singleton across all instances. Please ask for clarification if the question is not clear.
UPDATE
Following is my exact use case
public class SingletonProductIndexWriter {
private static final Logger LOG = Logger.getLogger(SingletonProductIndexWriter.class.getName());
public static IndexWriter getSingleIndexWriter() {
return IndexWriterHolder.INDEX_WRITER;
}
private static class IndexWriterHolder {
static PorterAnalyzer analyzer = new PorterAnalyzer();
static GaeDirectory index = new GaeDirectory(LuceneWorker.PRODUCTS);// create product index
static IndexWriterConfig config = GaeLuceneUtil.getIndexWriterConfig(LuceneWorker.LUCENE_VERSION, analyzer);
public static final IndexWriter INDEX_WRITER = getIndexWriter();
private static IndexWriter getIndexWriter() {
try {
LOG.info("Create single index writer for workers");
return new IndexWriter(index, config);
}catch(IOException e){
return null;
}
}
}
}
called as
IndexWriter writer = SingletonProductIndexWriter.getSingleIndexWriter();
For pertinent details see Stack Overflow thread: Worker threads cause Lucene LockObtainFailedException
Push and Pull queues are both processed by standard instances (you can target a module/frontend/backend in your queue.xml). Instances will scale up to meet the needs of both your normal traffic as well as your queues.
Singletons (in the classic sense portrayed here) are only unique to the classloader they are loaded by - they definitely are not unique across instances of your application on appengine - no state will be shared. Using this pattern you will have one singleton per appengine instance.
If you need to share state, you will need to use the datastore/cloud sql/something.

How to have a shared context per top-level process/thread without using InheritableThreadLocal?

I'd like to see if there's a good pattern for sharing a context across all classes and subthreads of a top-level thread without using InheritableThreadLocal.
I've got several top-level processes that each run in their own thread. These top-level processes often spawn temporary subthreads.
I want each top level process to have and manage it's own database connection.
I do not want to pass around the database connection from class to class and from thread to subthread (my associate calls this the "community bicycle" pattern). These are big top-level processes and it would mean editing probably hundreds of method signatures to pass around this database connection.
Right now I call a singleton to get the database connection manager. The singleton uses InheritableThreadLocal so that each top-level process has it's own version of it. While I know some people have problems with singletons, it means I can just say DBConnector.getDBConnection(args) (to paraphrase) whenever I need the correctly managed connection. I am not tied to this method if I can find a better and yet still-clean solution.
For various reasons InheritableThreadLocal is proving to be tricky. (See this question.)
Does anyone have a suggestion to handle this kind of thing that doesn't require either InheritableThreadLocal or passing around some context object all over the place?
Thanks for any help!
Update: I've managed to solve the immediate problem (see the linked question) but I'd still like to hear about other possible approaches. forty-two's suggestion below is good and does work (thanks!), but see the comments for why it's problematic. If people vote for jtahlborn's answer and tell me that I'm being obsessive for wanting to avoid passing around my database connection then I will relent, select that as my answer, and revise my world-view.
I haven't tested this, but the idea is to create a customized ThreadPoolExecutor that knows how to get the context object and use #beforeExecute() to transfer the context object to the thread that is going to execute the task. To be a nice citizen, you should also clear the context object in #afterEXecute(), but I leave that as an exercise.
public class XyzThreadPoolExecutor extends ThreadPoolExecutor {
public XyzThreadPoolExecutor() {
super(3, 3, 100, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new MyThreadFactory());
}
#Override
public void execute(Runnable command) {
/*
* get the context object from the calling thread
*/
Object context = null;
super.execute(new MyRunnable(context, command));
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
((MyRunnable)r).updateThreadLocal((MyThread) t);
super.beforeExecute(t, r);
}
private static class MyThreadFactory implements ThreadFactory {
#Override
public Thread newThread(Runnable r) {
return new MyThread(r);
}
}
private class MyRunnable implements Runnable {
private final Object context;
private final Runnable delegate;
public MyRunnable(Object context, Runnable delegate) {
super();
this.context = context;
this.delegate = delegate;
}
void updateThreadLocal(MyThread thread) {
thread.setContext(context);
}
#Override
public void run() {
delegate.run();
}
}
private static class MyThread extends Thread {
public MyThread(Runnable target) {
super(target);
}
public void setContext(Object context) {
// set the context object here using thread local
}
}
}
the "community bicycle" solution (as you call it) is actually much better than the global (or pseudo global) singleton that you are currently using. it makes the code testable and it makes it very easy to choose which classes use which context. if done well, you don't need to add the context object to every method signature. you generally ensure that all the "major" classes have a reference to the current context, and that any "minor" classes have access to the relevant "major" class. one-off methods which may need access to the context will need their method signatures updated, but most classes should have the context available through a member variable.
As a ThreadLocal is essentially a Map keyed on your thread, couldn't you implement a Map keyed on your thread name? All you then need is an effective naming strategy that meets your requirements.
As a Lisper, I very much agree with your worldview and would consider it a shame if you were to revise it. :-)
If it were me, I would simply use a ThreadGroup for each top-level process, and associate each connection with the group the caller is running in. If using in conjunction with thread pools, just ensure the pools use threads in the correct thread group (for instance, by having a pool per thread group).
Example implementation:
public class CachedConnection {
/* Whatever */
}
public class ProcessContext extends ThreadGroup {
private static final Map<ProcessContext, Map<Class, Object>> contexts = new WeakHashMap<ProcessContext, Map<Class, Object>>();
public static T getContext(Class<T> cls) {
ProcessContext tg = currentContext();
Map<Class, Object> ctx;
synchronized(contexts) {
if((ctx = contexts.get(tg)) == null)
contexts.put(tg, ctx = new HashMap<Class, Object>());
}
synchronized(ctx) {
Object cur = ctx.get(cls);
if(cur != null)
return(cls.cast(cur));
T new_t;
try {
new_t = cls.newInstance();
} catch(Exception e) {
throw(new RuntimeException(e));
}
ctx.put(cls, new_t);
return(new_t);
}
}
public static ProcessContext currentContext() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while(true) {
if(tg instanceof ProcessContext)
return((ProcessContext)tg);
tg = tg.getParent();
if(tg == null)
throw(new IllegalStateException("Not running in a ProcessContext"));
}
}
}
If you then simply make sure to run all your threads in a proper ProcessContext, you can get a CachedConnection anywhere by calling ProcessContext.getContext(CachedConnection.class).
Of course, as mentioned above, you would have to make sure that any other threads you may delegate work to also run in the correct ProcessContext, but I'm pretty sure that problem is inherent in your description -- you would obviously need to specify somehow which one of multiple contexts your delegation workers run in. If anything, it could be conceivable to modify ProcessContext as follows:
public class ProcessContext extends ThreadGroup {
/* getContext() as above */
private static final ThreadLocal<ProcessContext> tempctx = new ThreadLocal<ProcessContext>();
public static ProcessContext currentContext() {
if(tempctx.get() != null)
return(tempctx.get());
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while(true) {
if(tg instanceof ProcessContext)
return((ProcessContext)tg);
tg = tg.getParent();
if(tg == null)
throw(new IllegalStateException("Not running in a ProcessContext"));
}
}
public class RunnableInContext implements Runnable {
private final Runnable delegate;
public RunnableInContext(Runnable delegate) {this.delegate = delegate;}
public void run() {
ProcessContext old = tempctx.get();
tempctx.set(ProcessContext.this);
try {
delegate.run();
} finally {
tempctx.set(old);
}
}
}
public static Runnable wrapInContext(Runnable delegate) {
return(currentContext().new RunnableInContext(delegate));
}
}
That way, you could use ProcessContext.wrapInContext() to pass a Runnable which, when run, inherits its context from where it was created.
(Note that I haven't actually tried the above code, so it may well be full of typos.)
I would not support your world-view and jthalborn's idea on the count that its more testable even.
Though paraphrasing first what I have understood from your problme statement is like this.
There are 3 or 4 top-level processes (and they are basically having a thread of their own). And connection object is what is diffrenet in them.
You need some basic characteristic of Connection to be set up and done once.
The child threads in no way change the Connection object passe to them from top-level threads.
Here is what I propose, you do need the one tim,e set-up of you Connection but then in each of your top-level process, you do 1) further processing of that Connection 2) keep a InheriatbleThreadLocal (and the child process of your top-level thread will have the modified connection object. 3) Pass these threasd implementing classes. MyThread1, MyThread2, MyThread3, ... MyThread4 in the Executor. (This is different from the other linked question of yours that if you need some gating, Semaphore is a better approach)
Why I said that its not less testable than jthalborn's view is that in that case also you anyway again needs to provide mocked Connection object. Here too. Plus conecptually passing the object and keeping the object in ThreadLocal is one and the same (InheritableThreadLocal is a map which gets passed by java inbuilt way, nothing bad here I believe).
EDIT: I did keep in account that its a closed system and we are not having "free" threads tempring with connection

Factory of singleton objects: is this code thread-safe?

I have a common interface for a number of singleton implementations. Interface defines initialization method which can throw checked exception.
I need a factory which will return cached singleton implementations on demand, and wonder if following approach is thread-safe?
UPDATE1: Please don't suggest any 3rd partly libraries, as this will require to obtain legal clearance due to possible licensing issues :-)
UPDATE2: this code will likely to be used in EJB environment, so it's preferrable not to spawn additional threads or use stuff like that.
interface Singleton
{
void init() throws SingletonException;
}
public class SingletonFactory
{
private static ConcurrentMap<String, AtomicReference<? extends Singleton>> CACHE =
new ConcurrentHashMap<String, AtomicReference<? extends Singleton>>();
public static <T extends Singleton> T getSingletonInstance(Class<T> clazz)
throws SingletonException
{
String key = clazz.getName();
if (CACHE.containsKey(key))
{
return readEventually(key);
}
AtomicReference<T> ref = new AtomicReference<T>(null);
if (CACHE.putIfAbsent(key, ref) == null)
{
try
{
T instance = clazz.newInstance();
instance.init();
ref.set(instance); // ----- (1) -----
return instance;
}
catch (Exception e)
{
throw new SingletonException(e);
}
}
return readEventually(key);
}
#SuppressWarnings("unchecked")
private static <T extends Singleton> T readEventually(String key)
{
T instance = null;
AtomicReference<T> ref = (AtomicReference<T>) CACHE.get(key);
do
{
instance = ref.get(); // ----- (2) -----
}
while (instance == null);
return instance;
}
}
I'm not entirely sure about lines (1) and (2). I know that referenced object is declared as volatile field in AtomicReference, and hence changes made at line (1) should become immediately visible at line (2) - but still have some doubts...
Other than that - I think use of ConcurrentHashMap addresses atomicity of putting new key into a cache.
Do you guys see any concerns with this approach? Thanks!
P.S.: I know about static holder class idiom - and I don't use it due to ExceptionInInitializerError (which any exception thrown during singleton instantiation is wrapped into) and subsequent NoClassDefFoundError which are not something I want to catch. Instead, I'd like to leverage the advantage of dedicated checked exception by catching it and handling it gracefully rather than parse the stack trace of EIIR or NCDFE.
You have gone to a lot of work to avoid synchronization, and I assume the reason for doing this is for performance concerns. Have you tested to see if this actually improves performance vs a synchronized solution?
The reason I ask is that the Concurrent classes tend to be slower than the non-concurrent ones, not to mention the additional level of redirection with the atomic reference. Depending on your thread contention, a naive synchronized solution may actually be faster (and easier to verify for correctness).
Additionally, I think that you can possibly end up with an infinite loop when a SingletonException is thrown during a call to instance.init(). The reason being that a concurrent thread waiting in readEventually will never end up finding its instance (since an exception was thrown while another thread was initializing the instance). Maybe this is the correct behaviour for your case, or maybe you want to set some special value to the instance to trigger an exception to be thrown to the waiting thread.
Having all of these concurrent/atomic things would cause more lock issues than just putting
synchronized(clazz){}
blocks around the getter. Atomic references are for references that are UPDATED and you don't want collision. Here you have a single writer, so you do not care about that.
You could optimize it further by having a hashmap, and only if there is a miss, use the synchronized block:
public static <T> T get(Class<T> cls){
// No lock try
T ref = cache.get(cls);
if(ref != null){
return ref;
}
// Miss, so use create lock
synchronized(cls){ // singletons are double created
synchronized(cache){ // Prevent table rebuild/transfer contentions -- RARE
// Double check create if lock backed up
ref = cache.get(cls);
if(ref == null){
ref = cls.newInstance();
cache.put(cls,ref);
}
return ref;
}
}
}
Consider using Guava's CacheBuilder. For example:
private static Cache<Class<? extends Singleton>, Singleton> singletons = CacheBuilder.newBuilder()
.build(
new CacheLoader<Class<? extends Singleton>, Singleton>() {
public Singleton load(Class<? extends Singleton> key) throws SingletonException {
try {
Singleton singleton = key.newInstance();
singleton.init();
return singleton;
}
catch (SingletonException se) {
throw se;
}
catch (Exception e) {
throw new SingletonException(e);
}
}
});
public static <T extends Singleton> T getSingletonInstance(Class<T> clazz) {
return (T)singletons.get(clazz);
}
Note: this example is untested and uncompiled.
Guava's underlying Cache implementation will handle all caching and concurrency logic for you.
This looks like it would work although I might consider some sort of sleep if even a nanosecond or something when testing for the reference to be set. The spin test loop is going to be extremely expensive.
Also, I would consider improving the code by passing the AtomicReference to readEventually() so you can avoid the containsKey() and then putIfAbsent() race condition. So the code would be:
AtomicReference<T> ref = (AtomicReference<T>) CACHE.get(key);
if (ref != null) {
return readEventually(ref);
}
AtomicReference<T> newRef = new AtomicReference<T>(null);
AtomicReference<T> oldRef = CACHE.putIfAbsent(key, newRef);
if (oldRef != null) {
return readEventually(oldRef);
}
...
The code is not generally thread safe because there is a gap between the CACHE.containsKey(key) check and the CACHE.putIfAbsent(key, ref) call. It is possible for two threads to call simultaneously into the method (especially on multi-core/processor systems) and both perform the containsKey() check, then both attempt to do the put and creation operations.
I would protect that execution of the getSingletonInstnace() method using either a lock or by synchronizing on a monitor of some sort.
google "Memoizer". basically, instead of AtomicReference, use Future.

Categories