ThreadStatic与ThreadLocal <T>:泛型是否优于属性?


Answers:


112

评论中提到的博客文章并没有明确,但是我发现非常重要的一点是,[ThreadStatic]它不会自动为每个线程初始化事情。例如,假设您有以下内容:

[ThreadStatic]
private static int Foo = 42;

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

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

我认为,使用[ThreadStatic]代替没有任何优势ThreadLocal<T>


20
除了可能ThreadLocal<T>在.NET 4及更高版本中可用,而且ThreadStatic属性在3.5及以下版本中也可用。
Jeroen 2014年

2
而且,如果您不使用初始化程序来设置值,而是在初始化后的某个晚些时候对其进行设置,则使用[ThreadStatic]在语法上更干净。
以为

9
而且除了ThreadLocal<T>实施IDisposable和通常迫使您也实施之外IDisposable,这迫使您的呼叫者处置您并因此也实施IDisposable...
Stefan Steinegger

4
@StefanSteinegger:我会非常小心地使用ThreadLocalThreadStatic与池线程一起使用。这些值将在池线程的整个生命周期中保留,而不仅仅是分配给您的任务所用。这可能会以一些非常明显的方式给您带来麻烦。有关更多信息,请参见stackoverflow.com/questions/561518/…和类似问题。
Jim Mischel

3
例子中的字段也不能声明static吗?见msdn.microsoft.com/en-us/library/...
entheh

39

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

在此处输入图片说明


15

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。


1
完整的文章可以在这里找到。
DanielDušek18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.