ThreadStatic 与 ThreadStatic 对比ThreadLocal<T>:泛型比属性好吗?

Posted

技术标签:

【中文标题】ThreadStatic 与 ThreadStatic 对比ThreadLocal<T>:泛型比属性好吗?【英文标题】:ThreadStatic v.s. ThreadLocal<T>: is generic better than attribute? 【发布时间】:2013-08-22 10:27:01 【问题描述】:

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

【问题讨论】:

见reedcopsey.com/2009/11/12/… - 我不明白这与反射有什么关系...... 【参考方案1】:

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

[ThreadStatic]
private static int Foo = 42;

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

ThreadLocal&lt;T&gt; 通过让您提供一个在第一次访问项目之前运行的初始化函数(如 Reed 的博客所示)解决了这个问题。

在我看来,使用[ThreadStatic] 代替ThreadLocal&lt;T&gt; 没有任何优势。

【讨论】:

除了ThreadLocal&lt;T&gt; 可能在 .NET 4 及更高版本中可用,the ThreadStatic attribute 在 3.5 及更低版本中也可用。 如果你不使用初始化器来设置值,而是在初始化后的某个时间点设置它,使用 [ThreadStatic] 在语法上更简洁。 除了 ThreadLocal&lt;T&gt; 实现 IDisposable 并且通常强制您实现 IDisposable 之外,这会迫使您的调用者处置您,因此也实现 IDisposable ...跨度> @StefanSteinegger:我会非常小心地将ThreadLocalThreadStatic 与池线程一起使用。这些值将在池线程的整个生命周期中保留,而不仅仅是您分配的任务。这可能会以一些非常不明显的方式给你带来麻烦。有关详细信息,请参阅 ***.com/questions/561518/… 和类似问题。 示例中的字段不应该也声明为static吗?见msdn.microsoft.com/en-us/library/…【参考方案2】:

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

【讨论】:

【参考方案3】:

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

在上面的 sn-p 中,我们为每个线程(包括主线程)提供了一个单独的 value 副本。

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

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

【讨论】:

完整文章可以在here找到。

以上是关于ThreadStatic 与 ThreadStatic 对比ThreadLocal<T>:泛型比属性好吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 async/await 的 ThreadStatic 变量

谈谈ThreadStatic

这是初始化 [ThreadStatic] 的线程安全方式吗?

在哪里存储当前 WCF 调用的数据? ThreadStatic 安全吗?

所有活动 ThreadLocal<T> 和 [ThreadStatic] 引用的列表

基础之ThreadStatic