C# ThreadLocal 的使用误区

2022年8月4日 1666点热度 1人点赞 0条评论
内容纲要

如下面代码:

[ThreadStatic]
private bool HasCreated = false;
[ThreadStatic]
private int Value = 0;

void Main()
{
    ThreadLocal<string> a = new ThreadLocal<string>(() =>
    {
        if (HasCreated) return Value.ToString();
        else
        {
            Value = Thread.CurrentThread.ManagedThreadId;
            HasCreated = true;
            return Value.ToString();
        }
    });

    new Thread(() =>
    {
        Console.WriteLine("代码1 值:" + a.Value);
    }).Start();

    new Thread(() =>
    {
        Console.WriteLine("代码2 值:" + a.Value);
    }).Start();
}

设想上,两个线程输出的数字应该是不一样的,但是无论怎么运行,两个线程输出的数字都是一样的。
开始以为是两个线程间隔时间太短,造成两个代码的线程复用了。

然后改代码,将两个线程同时运行。

![file](https://www.whuanle.cn/wp-content/uploads/2022/08/image-1659579697218.png)[ThreadStatic]
private bool HasCreated = false;
[ThreadStatic]
private int Value = 0;

void Main()
{
    ThreadLocal<string> a = new ThreadLocal<string>(() =>
    {
        if (HasCreated) return Value.ToString();
        else
        {
            Value = Thread.CurrentThread.ManagedThreadId;
            HasCreated = true;
            return Value.ToString();
        }
    });

    new Thread(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("代码1 值:" + a.Value);
    }).Start();

    new Thread(() =>
    {
        Console.WriteLine("代码2 值:" + a.Value);
        Thread.Sleep(1000);
    }).Start();
}

但是,输出还是一模一样。
看了一下 ThreadLocal 的源码,其 Func<T> 是延迟执行的,只有使用 .Value 的时候才会执行。

file

为了更好判断问题,再次改代码:

[ThreadStatic]
private bool HasCreated = false;
[ThreadStatic]
private int Value = 0;

void Main()
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    ThreadLocal<string> a = new ThreadLocal<string>(() =>
    {
        if (HasCreated) return Value.ToString();
        else
        {
            Value = Thread.CurrentThread.ManagedThreadId;
            HasCreated = true;
            return Value.ToString();
        }
    });

    new Thread(() =>
    {
        Console.WriteLine("代码1 线程id:" + Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine("代码1 值:" + a.Value);
        Thread.Sleep(1000);
    }).Start();

    new Thread(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("代码2 线程id:" + Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine("代码2 值:" + a.Value);

    }).Start();

    Thread.Sleep(2000);
}

file

可以看到,Value 不是 Main 的线程 id,是代码1 的 id。
一旦有一个线程设置了 Value,后面的线程都会跟着使用这个 HasCreateValue
但是里面的代码 .Value 每次都会执行 Func<T> ,但是为什么取到的 HasCreate 是相同的值?

emmm....

原来是忘记了加上 static。。。
[ThreadStatic] 修饰的变量,只能是静态字段。

[ThreadStatic]
private static bool HasCreated = false;
[ThreadStatic]
private static int Value = 0;

file

痴者工良

高级程序员劝退师

文章评论