Thread-local storage in Java and C#
Wednesday, June 11, 2003 11:01 PM

I first came to know the magic of thread-local storage through some old version of WebLogic--whatever was current in 2000. Anywhere in the EJB container, you could call User.currentUser() and with no more effort than that you'd get the instance of User that was responsible for the current request. Thus, two different threads of execution could call that same static method and receive different results. For a humble web developer who was just starting out with Java, this was rather mind-blowing.

Older and wiser now, there's no mystery to thread-local storage; it's rather a simple mechanism if you think about it. All that's happening is a mapping between threads and values. Java exposes it via the ThreadLocal class:

// Java code
class User {
  // whatever instance members...
  private String getUsername() { ... }

  private static ThreadLocal currentUser = new ThreadLocal();
  public static User currentUser() { return (User)currentUser.get(); }
  public static void setCurrentUser(User user) { currentUser.set(user); }

At the beginning of a request you'd just have to make sure to call User.setCurrentUser(user), and for the rest of the request's lifetime you could get access to that user using User.currentUser(). (For the moment, let's forget about thread pooling and the problems that might create.)

Basically the ThreadLocal acts like a hashtable, except you don't get to specify the key in the get/put methods, because the key is always the current thread. (In Sun's JVM, it isn't actually implemented this way; each Thread instance has an area to put thread-local variables. Makes for easier cleanup when the thread dies. For the purposes of this discussion, though, it makes little difference which way it's implemented.)

If you're familiar with Java's thread-local storage already, none of the above is news. What you may find interesting, though, is one of the mechanisms C#/.NET offers for thread-local storage:

// C# code
class User {
  // whatever instance members...
  private string GetUsername() { ... }

  [ThreadStatic] private static User currentUser;
  public static User currentUser() { return currentUser; }
  public static void setCurrentUser(User user) { currentUser = user; }

See what's happening here? Simply by adding the ThreadStatic attribute to the static member, every access or assignment of that field gains thread-local semantics. Now someone please explain to me how this actually works!? My only guess is that the compiler and/or the CLR have specific knowledge about the ThreadStatic attribute and handle themselves accordingly. If there's a way to do anything like this yourself using user-defined attributes, it's beyond my (admittedly rather limited) imagination.

Assuming that I'm right and the compiler/CLR have knowledge of ThreadStatic built in, this kind of typifies the difference between Java and .NET (and I guess, Microsoft in general). The Microsoft approach results in a more convenient, concise syntax, as it saves a couple of explicit casts. However, it also involves a "magic" attribute that only has its powers because of specific support in the compiler/CLR. The Java approach requires no language or runtime support; the whole notion of ThreadLocals exists at a higher layer (you can see this for yourself in the JDK's Java source).

After almost seven months of programming in C# full-time, I'm still finding new language features all the time that surprise me. A couple of weeks ago, it was the "add/remove" keywords that let you override the += and -= operators for events. Yesterday it was ThreadStatic. C# may look a lot like Java on first glance, but it is a significantly larger language with more "magical" features. Whether that's good or bad is up to you; I, for one, think small is beautiful.

One last thing. If ThreadStatic does have compiler/CLR support, shouldn't it really be a keyword? That way at least it's obvious that there is something very un-attribute-like going on (the same could go for a couple of other magic .NET attributes, like Conditional and... well, I can't remember the others at the moment).

// pretend C# code
private threadstatic User currentUser;