Skip to content

线程本地存储(Thread Local Storage, TLS)(2)ThreadStaticAttribute

🏷️ C# 学习 C#

申明了 ThreadStaticAttribute 特性的静态变量,会被.NET 作为线程独享的数据来使用。

示例代码

ThreadStaticSample.cs

cs
using System;
using System.Threading;

namespace ThreadStaticSample
{
    class ThreadStaticSample
    {
        /// <summary>
        /// 值类型的线程静态数据
        /// </summary>
        [ThreadStatic]
        static int _threadid = 0;
        /// <summary>
        /// 引用类型的线程静态数据
        /// </summary>
        static Ref _refthreadid = new Ref();

        public static void DoWork()
        {
            _threadid = Thread.CurrentThread.ManagedThreadId;
            _refthreadid._id = Thread.CurrentThread.ManagedThreadId;

            Console.WriteLine("[{0}线程]:线程静态变量:{1},线程静态引用变量:{2}",
                Thread.CurrentThread.ManagedThreadId.ToString(),
                _threadid,
                _refthreadid._id);
            Thread.Sleep(1000);
            Console.WriteLine("[{0}线程]:线程静态变量:{1},线程静态引用变量:{2}",
                Thread.CurrentThread.ManagedThreadId.ToString(),
                _threadid,
                _refthreadid._id);

        }
    }
}

Ref.cs

cs
namespace ThreadStaticSample
{
    /// <summary>
    /// 简单引用类型
    /// </summary>
    class Ref
    {
        public int _id;
    }
}

Program.cs

cs
using System;
using System.Threading;

namespace ThreadStaticSample
{
    class Program
    {
        static void Main(string args)
        {
            Console.WriteLine("现在开始测试线程静态字段");
            // 开辟 5 个线程来同时运行
            // 这里不适合用线程池,
            // 因为线程池内的线程会被反复使用,
            // 导致线程 ID 一致
            for (int i = 0; i < 5; i++)
            {
                Thread thread = new Thread(ThreadStaticSample.DoWork);
                thread.Start();
            }
            Console.Read();
        }
    }
}

输出结果

现在开始测试线程静态字段
[3线程]:线程静态变量:3,线程静态引用变量:3
[5线程]:线程静态变量:5,线程静态引用变量:5
[7线程]:线程静态变量:7,线程静态引用变量:7
[6线程]:线程静态变量:6,线程静态引用变量:6
[4线程]:线程静态变量:4,线程静态引用变量:4
[7线程]:线程静态变量:7,线程静态引用变量:4
[3线程]:线程静态变量:3,线程静态引用变量:4
[5线程]:线程静态变量:5,线程静态引用变量:4
[4线程]:线程静态变量:4,线程静态引用变量:4
[6线程]:线程静态变量:6,线程静态引用变量:4

运行时发现一个奇怪的现象,对 _refthreadid 变量追加 [ThreadStatic] 特性后,运行会出 NullReferenceException 异常。

修改后的 ThreadStaticSample.cs

cs
using System;
using System.Threading;

namespace ThreadStaticSample
{
    class ThreadStaticSample
    {
        /// <summary>
        /// 值类型的线程静态数据
        /// </summary>
        [ThreadStatic]
        static int _threadid = 0;
        /// <summary>
        /// 引用类型的线程静态数据
        /// </summary>
        [ThreadStatic]
        static Ref _refthreadid = new Ref();

        public static void DoWork()
        {
            _threadid = Thread.CurrentThread.ManagedThreadId;
            if (_refthreadid == null)
            {
                _refthreadid = new Ref();
            }
            _refthreadid._id = Thread.CurrentThread.ManagedThreadId;

            Console.WriteLine("[{0}线程]:线程静态变量:{1},线程静态引用变量:{2}",
                Thread.CurrentThread.ManagedThreadId.ToString(),
                _threadid,
                _refthreadid._id);
            Thread.Sleep(1000);
            Console.WriteLine("[{0}线程]:线程静态变量:{1},线程静态引用变量:{2}",
                Thread.CurrentThread.ManagedThreadId.ToString(),
                _threadid,
                _refthreadid._id);

        }
    }
}

输出结果

现在开始测试线程静态字段
[3线程]:线程静态变量:3,线程静态引用变量:3
[5线程]:线程静态变量:5,线程静态引用变量:5
[7线程]:线程静态变量:7,线程静态引用变量:7
[6线程]:线程静态变量:6,线程静态引用变量:6
[4线程]:线程静态变量:4,线程静态引用变量:4
[3线程]:线程静态变量:3,线程静态引用变量:3
[7线程]:线程静态变量:7,线程静态引用变量:7
[4线程]:线程静态变量:4,线程静态引用变量:4
[5线程]:线程静态变量:5,线程静态引用变量:5
[6线程]:线程静态变量:6,线程静态引用变量:6