Playing with ThreadLocal

When you work on enterprise applications, TheadLocal variables are something you don’t see very often. You see them once in a while, but you never have to deal with them directly. So, in this short post I want to illustrate how ThreadLocal variables work.

As the name suggests, this variables are local to the thread. So for example if you set some value in thread1 and then you ask for the value while running in thread2 you will get null (assuming that no one set some value in this thread before) because that value is only visible inside thread1.

Let’s see how this works in code!

import java.util.concurrent.{Executor, Executors}


object ThreadLocalTest {

  class TestClass(name: String){

    private[this] val tl : ThreadLocal[String] = new ThreadLocal()

    def setLocal(s: String): Unit = {
      println("Setting value '" + s + "' in " + Thread.currentThread().getName)
      tl.set(s)
    }

    def getLocal: String = {
      val s = tl.get()
      println("Getting value '" + s + "' in " + Thread.currentThread().getName)
      s
    }

  }

  def main(args: Array[String]): Unit = {
    val testObject = new TestClass("TestClass 1")

    val t1 = Executors.newSingleThreadExecutor()
    val t2 = Executors.newSingleThreadExecutor()

    execute{testObject.setLocal("th1!!")}(t1)
    Thread.sleep(1000) // sleep main thread to make sure the previous execution has run
    execute{testObject.setLocal("th2!!")}(t2)
    Thread.sleep(1000)
    execute{testObject.getLocal}(t1)
    Thread.sleep(1000)
    execute{testObject.getLocal}(t2)
    Thread.sleep(1000)
    println("In Main " + testObject.getLocal)

  }

  /**
    * Executes the given task in the given executor
    */
  private def execute(f: => Unit)( e: Executor) = {
    e.execute(new Runnable {
      override def run(): Unit = f
    })
  }
}

Once we run the program, we get:

Setting value 'th1!!' in pool-1-thread-1
Setting value 'th2!!' in pool-2-thread-1
Getting value 'th1!!' in pool-1-thread-1
Getting value 'th2!!' in pool-2-thread-1
Getting value 'null' in main
In Main null

As you can see, the value that is set in a specific thread is only visible in that thread, and because we never call setlocal in the main thread we get null when we call getLocal.