99

[ThreadStatic]使用属性定义,而ThreadLocal<T>使用泛型。为什么选择不同的设计解决方案?在这种情况下,使用泛型优于属性有什么优点和缺点?

4

3 回答 3

121

评论中提到的博客文章没有明确说明,但我发现非常重要的是,[ThreadStatic]它不会自动为每个线程初始化事物。例如,假设你有这个:

[ThreadStatic]
private static int Foo = 42;

使用它的第一个线程将看到Foo初始化为42. 但后续线程不会。初始化程序仅适用于第一个线程。因此,您最终不得不编写代码来检查它是否已初始化。

ThreadLocal<T>通过让您提供在第一次访问项目之前运行的初始化函数(如 Reed 的博客所示)来解决该问题。

在我看来,使用[ThreadStatic]而不是ThreadLocal<T>.

于 2013-08-20T14:06:42.810 回答
40

ThreadStatic 仅在第一个线程上初始化,ThreadLocal 对每个线程进行初始化。下面是简单的演示:

    public static ThreadLocal<int> _threadlocal =
        new ThreadLocal<int>(() =>
        {
            return Thread.CurrentThread.ManagedThreadId;
        });

    public static void Main()
    {
        new Thread(() =>
        {
            for (int x = 0; x < _threadlocal.Value; x++)
            {
                Console.WriteLine("First Thread: {0}", x);
            }
        }).Start();

        new Thread(() =>
        {
            for (int x = 0; x < _threadlocal.Value; x++)
            {
                Console.WriteLine("Second Thread: {0}", x);
            }
        }).Start();

        Console.ReadKey();
    }

在此处输入图像描述

于 2014-10-30T01:27:06.767 回答
16

ThreadStatic 背后的主要思想是为每个线程维护一个单独的变量副本

class Program
    {
        [ThreadStatic]
        static int value = 10;

        static void Main(string[] args)
        {
            value = 25;

            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);
            Console.ReadKey();
        }
    }

在上面的代码片段中,我们value对每个线程都有一个单独的副本,包括主线程。

在此处输入图像描述

因此,ThreadStatic 变量将在除创建它的线程之外的其他线程上初始化为其默认值。

如果我们想以自己的方式在每个线程上初始化变量,请使用 ThreadLocal。

于 2016-09-27T02:07:39.777 回答