3
\$\begingroup\$

In my application there is a "config" object that is accessbile by multiple threads concurrently. It is a single object (singleton) injected by the DI in the "dependents". Until now, this (the "config") object was immutable which makes it inherently thread-safe. However, there is a new requirement that the "config" should be periodically "refreshed/updated". I wrote a wrapper (decorator) that refreshes itself (from a configProvider), and the refresh happens on the fly, when a method gets called (if the certian amount of time has passed) The wrapper should be thread safe and non-blocking.

Any (concurrency) issues with the following code?

package xyz;
import java.util.concurrent.atomic.AtomicBoolean;
/**
 * Implementation of {@link IMyModuleConfig} that periodically refreshes itself from the provided
 * {@link IConfiguration}.
 * The refresh is done on-the-fly when some method is called, it is thread safe.
 *
 * @Threadsafe
 */
public class MyModuleRefreshableConfig implements IMyModuleConfig {
 private IMyModuleConfig configBean; // Decorated object, Immutable, non-final should be properly fenced 
 private long lastRefreshTime; // time when we refreshed the configuration last, non-final should be properly fenced 
 private final IConfiguration configProvider; // refresh source
 private final long refreshInterval; // how often we refresh
 private final AtomicBoolean refreshConfigMutex; // if true, a thread is refreshing configuration right now
 public MyModuleRefreshableConfig(IConfiguration configProvider, long refreshInterval) {
 refreshConfigMutex = new AtomicBoolean(false);
 this.configBean = refreshConfig();
 this.lastRefreshTime = System.currentTimeMillis();
 // Do not re-arrange, the assignment to final field latter in the constructor serves as a "store fence"
 this.configProvider = configProvider;
 this.refreshInterval = refreshInterval;
 }
 @Override
 public boolean getMyBoolean() {
 refreshConfigIfNeeded(); // full fence
 return this.configBean.getMyBoolean();
 }
 @Override
 public int getTimeout() {
 refreshConfigIfNeeded(); // full fence
 return this.configBean.getTimeout();
 }
 private void refreshConfigIfNeeded() {
 boolean aquired = refreshConfigMutex.compareAndSet(false, true); // full fence
 if (aquired) { // critical section starts, if some thread is in just continue, no need to wait
 long cTime = System.currentTimeMillis();
 boolean shouldRefresh = (cTime - lastRefreshTime) > refreshInterval;
 if (shouldRefresh) {
 lastRefreshTime = cTime;
 configBean = refreshConfig();
 }
 refreshConfigMutex.set(false); // critical section ends, write fence
 }
 }
 private IMyModuleConfig refreshConfig() {
 // creates new immutable IMyModuleConfig with values provided by configProvider
 }
}
asked May 1, 2014 at 20:55
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

As long as you are 100% certain that all threads will use the same instance of MyModuleRefreshableConfig, this code should work. Just to be certain I would make the refreshConfigMutexstatic:

private static final AtomicBoolean refreshConfigMutex;
public MyModuleRefreshableConfig(IConfiguration configProvider, long refreshInterval) {
 synchronized {
 if (refreshConfigMutex == null) {
 refreshConfigMutex = new AtomicBoolean(false);
 }
 }
 ....
}
answered May 2, 2014 at 13:28
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.