First off these are two different objects altogether, ThreadStatic is actually ThreadStaticAttribute and you mark a static variable with the attribute. Whereas ThreadLocal is a generic class.
So why are we looking at both in the one post?
Both ThreadStatic and ThreadLocal are used to allow us to declare thread specific values/variables.
ThreadStatic
A static variable marked with the ThreadStatic attribute is not shared between threads, therefore each thread gets it’s own instance of the static variable.
Let’s look at some code
[ThreadStatic] static int value; static void Main() { Task t1 = Task.Run(() => { value++; Console.WriteLine("T1: " + value); }); Task t2 = Task.Run(() => { value++; Console.WriteLine("T2: " + value); }); Task t3 = Task.Run(() => { value++; Console.WriteLine("T3: " + value); }); Task.WaitAll(t1, t2, t3); }
The output from this (obviously the ordering may be different) is
T3: 1 T1: 1 T2: 1
One thing to watch out for is that if we initialize the ThreadStatic variable, for example if we write the following
[ThreadStatic] static int value = 10;
you need to be aware that this
For example, if we change the code very slightly to get
[ThreadStatic] static int value = 10; static void Main() { Task t1 = Task.Run(() => { value++; Console.WriteLine("T1: " + value); }); Task t2 = Task.Run(() => { value++; Console.WriteLine("T2: " + value); }); Task t3 = Task.Run(() => { value++; Console.WriteLine("T3: " + value); }); Console.WriteLine("Main thread: " + value); Task.WaitAll(t1, t2, t3); }
The output will look something like
Main thread: 10 T2: 1 T1: 1 T3: 1
Finally as, by definition each variable is per thread, operations upon the instance of the variable are thread safe.
ThreadLocal
Like the ThreadStatic attribute, the ThreadLocal class allows us to declare a variable which is not shared between threads, one of the extra capabilities of this class is that we can initialize each instance of the variable as the class the supplied factory method to create and/or initialize the value to be returned. Also, unlike ThreadStatic which only works on static fields, ThreadLocal can be applied to static or instance variables.
Let’s look at the code
static void Main() { ThreadLocal<int> local = new ThreadLocal<int>(() => { return 10; }); Task t1 = Task.Run(() => { local.Value++; Console.WriteLine("T1: " + local.Value); }); Task t2 = Task.Run(() => { local.Value++; Console.WriteLine("T2: " + local.Value); }); Task t3 = Task.Run(() => { local.Value++; Console.WriteLine("T3: " + local.Value); }); Task.WaitAll(t1, t2, t3); local.Dispose(); }
The output order may be different, but the output will read something like
T2: 11 T3: 11 T1: 11
As you can see, each thread altered their own instance of the thread local variable and more over we were able to set the default value to 10.
The ThreadLocal class implements IDisposable, so we should Dispose of it when we’ve finished with it.
Apart from Dispose all methods and protected members are thread safe.