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:
#!java
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:
#!java
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();     
  }  
} 

To get the application instance, just call the static getInstance() method.

MyApplication.getInstance().doBlahBlah();  
0 Attachments
30822 Views
Average (10 Votes)
Comments