Outdated content

ThreadLocal Pattern

Note: This article is outdated. ThreadLocal should be implemented using HttpServletRequestListener instead of TransactionListener. Note2: HttpServletRequestListener example added. Please review. 2011-01-03

The ThreadLocal pattern is used to easily keep track of application instances or locale settings throughout the handling of a request. The ThreadLocal class works like a static variable, with the exception that it is only bound to the current thread! This allows us to use static variables in a thread-safe way.

The usual use-cases are:

 MyApplication.getCurrent().callSomethingOnTheCurrentApplicationInstance(); 

or say that we have a Lang-class that handles translations and so we need to keep track of the locale for the currently executing thread:

 Lang.getThreadLocale(); 

If you are creating child threads and you wish to use the values stored in the

ThreadLocal
, you should consider using InheritableThreadLocal which provides inheritance of the values from the parent thread to a child thread.

An example #

Here is an example of an application keeping a "static" reference to the current application instance and updating the locale for the current user with each request:

public class MyApplication extends Application implements TransactionListener {
  private static ThreadLocal<MyApplication> currentApplication = new ThreadLocal<MyApplication>();
  
  @Override	
  public void init() {
    setCurrent(this); // So that we immediately have access to the current application//

    // initialize mainWindow and other stuff//
    // Register a transaction listener that updates our ThreadLocal with each request		
    if (getContext() != null) {
      getContext().addTransactionListener(this);
    }		
  }

  /**
   * @return the current application instance
   */	
  public static MyApplication getCurrent() {	
    return currentApplication.get();
  }

  /**
   * Set the current application instance
   */
  public static void setCurrent(MyApplication application) {
    currentApplication.set(application);
  }

  /**
   * Remove the current application instance
   */
  public static void removeCurrent() {
    currentApplication.remove();
  }

  /**
   * TransactionListener
   */
  public void transactionStart(Application application, Object transactionData) {
    if (application == this) {
      MyApplication.setCurrent(this);
      // Store current users locale
      Lang.setLocale(getLocale());
    }	
  }

  public void transactionEnd(Application application, Object transactionData) {
    if (application == this) {
      // Remove locale from the executing thread
      removeCurrent();
    }
  }

  @Override
  public void close() {
    getContext().removeTransactionListener(this);
    super.close();
  }
}

Updated Example using HttpServletRequestListener #

Using HttpServletRequestListener simplifies the code a bit:

public class MyApplication extends Application implements HttpServletRequestListener {
  private static ThreadLocal<MyApplication> threadLocal = new ThreadLocal<MyApplication>();

  @Override
  public void init() {
    setInstance(this); // So that we immediately have access to the current application
  }

  // return the current application instance
  public static MyApplication getInstance() {
    return threadLocal.get();
  }

  // Set the current application instance
  public static void setInstance(MyApplication application) {
    threadLocal.set(application);
  }

  @Override
  public void onRequestStart(HttpServletRequest request, HttpServletResponse response) {
    MyApplication.setInstance(this);
  }

  @Override
  public void onRequestEnd(HttpServletRequest request, HttpServletResponse response) {
    threadLocal.remove();
  }
}
0 Attachments
36143 Views
Average (10 Votes)
Comments