Is the following utility class thread safe?

First, consider the utility class (most javadoc was removed simply as an example):

public class ApplicationContextUtils { /** * The application context; care should be taken to ensure that 1) this * variable is assigned exactly once (in the * {@link #setContext(ApplicationContext)} method, 2) the context is never * reassigned to {@code null}, 3) access to the field is thread-safe (no race * conditions can occur) */ private static ApplicationContext context = null; public static ApplicationContext getContext() { if (!isInitialized()) { throw new IllegalStateException( "Context not initialized yet! (Has the " + "ApplicationContextProviderBean definition been configured " + "properly and has the web application finished " + "loading before you invoked this method?)"); } return context; } public static boolean isInitialized() { return context == null; } @SuppressWarnings("unchecked") public static <T> T getBean(final String name, final Class<T> requiredType) { if (requiredType == null) { throw new IllegalArgumentException("requiredType is null"); } return (T) getContext().getBean(name, requiredType); } static synchronized void setContext(final ApplicationContext theContext) { if (theContext == null) { throw new IllegalArgumentException("theContext is null"); } if (context != null) { throw new IllegalStateException( "ApplicationContext already initialized: it cannot be done twice!"); } context = theContext; } private ApplicationContextUtils() { throw new AssertionError(); // NON-INSTANTIABLE UTILITY CLASS } } 

Finally, there is the following helper Spring managed bean that actually calls the setContext method:

 public final class ApplicationContextProviderBean implements ApplicationContextAware { public void setApplicationContext( final ApplicationContext applicationContext) throws BeansException { ApplicationContextUtils.setContext(applicationContext); } } 

Spring will call the setApplicationContext method once after starting the application. Assuming nincompoop was not previously called ApplicationContextUtils.setContext (), which should block the context link in the utility class, allowing getContext () calls to succeed (this means that isInitialized () returns true).

I just want to know if this class violates any principles of good coding practice regarding thread safety in particular (but other nonsense can be found).

Thank you for helping me become a better programmer, StackOverflow!

Regards, LES

PS I did not deal with why I need this utility class. It’s enough that I really had a legitimate need to access it from a static context anywhere in the application (after loading the Spring context).

+3
java spring multithreading static thread-safety
source share
2 answers

Not. This is not a safe thread.

It is written to the variable of the context class, visibility is not guaranteed for threads that read this variable through getContext() .

At the very least, declare context equal to volatile . Ideally, redefine context as AtomicReference by defining this call:

 if(!context.compareAndSet(null, theContext)) throw new IllegalStateException("The context is already set."); 

Here is a more complete example:

 public class ApplicationContextUtils { private static final AtomicReference<ApplicationContext> context = new AtomicReference<ApplicationContext>(); public static ApplicationContext getContext() { ApplicationContext ctx = context.get(); if (ctx == null) throw new IllegalStateException(); return ctx; } public static boolean isInitialized() { return context.get() == null; } static void setContext(final ApplicationContext ctx) { if (ctx == null) throw new IllegalArgumentException(); if (!context.compareAndSet(null, ctx)) throw new IllegalStateException(); } public static <T> T getBean(final String name, final Class<T> type) { if (type == null) throw new IllegalArgumentException(); return type.cast(getContext().getBean(name, type)); } private ApplicationContextUtils() { throw new AssertionError(); } } 

Note that in addition to thread safety, this also provides type safety by using the Class instance passed to the getBean() method.

I'm not sure how you plan to use the isInitialized() method; this does not seem very useful to me, because as soon as you call it, the condition may change, and you do not have a good way to receive a notification.

+8
source share

Spring already has a class called ContextSingletonBeanFactoryLocator that invokes static access to the ApplicationContext for you. At the very least, using this class can save you anxiety if your user approach is thread safe.

However, it is a little confusing to use this class first, as it touches a little there. You can see this blog post for more information on how this call works.

+1
source share

All Articles