网上有很多关于ThreadLocal的文章,但是很多都是介绍java中的ThreadLocal。今天我来介绍.net中的ThreadLocal的实现原理。
ThreadLocal定义
1:提供数据线程的本地存储,也就是每个线程都有一个变量副本,而且互不影响。
2:为了有一个直观的感受,看一段代码:
3:此段代码的执行结果如下:其中,3、1代表线程号,后面的王五、李四代表这两个线程对应的各自的值。通过结果可以发现,虽然线程3将值改成了王五,但是当线程1执行的时候,仍然能够输出自己所设置的值,也就是李四。为什么会实现这个效果,继续看。
原理
1:通过查看ThreadLocal源码发现,实现每个线程都有一个变量副本的关键代码如下:
是**[ThreadStatic]**使每个线程都有一个变量副本。
2:那么问题来了,[ThreadStatic]是怎么做到的,使每个线程拥有一个变量副本呢?
答案:[ThreadStatic]改变了Clr的默认行为。默认情况下,静态变量是线程共享的,但是当Clr看到静态变量上添加了[ThreadStatic]特性时,就会对该变量做特殊的处理,使得每一个线程单独创一个变量副本。
3:那么问题又来了,为什么是改变了Clr的默认行为,而不是通过编译器生成的IL(中间码)实现的?
3.1:[ThreadStatic]源代码如下:通过这段代码,我们可以发现[ThreadStatic]只是一个定义,没有任何实现。
3.2:看一下我的代码实现,如下:
通过ilDasm工具查看,生成的中间码也没有做关于线程本地存储的代码。因此通过排除法,可以证明是通过改变Clr的默认行为来实现线程本地存储的。
使用场景
1:存储用户session。
2:数据库连接。
3:线程内上下文管理等等。
心得
1:并不是所有的功能都是通过代码实现的。
2:Clr的行为是可以改变的。
3:对于多线程资源共享的问题:不仅仅可以通过加锁的方式来解决,也可以通过让线程本地存储来解决。
参考文章
1:https://stackoverflow.com/questions/5227676/how-does-the-threadstatic-attribute-work
2:https://referencesource.microsoft.com/#mscorlib/system/threading/ThreadLocal.cs,
b0c23fc7e6f66cf4
3:https://referencesource.microsoft.com/#mscorlib/system/threadstaticattribute.cs,
14e92e6a6cd64604
4:https://www.cnblogs.com/fengzheng/p/8690253.html