多线程中Local Store Slot(本地存储槽)[转]
1. 使用ThreadStatic特性
ThreadStatic特性是最简单的TLS使用,且只支持静态字段,只需要在字段上标记这个特性就可以了:
- [ThreadStatic]
- static string str = "hehe";
- static void Main()
- {
- //另一个线程只会修改自己TLS中的str变量
- Thread th = new Thread(() => { str = "Mgen"; Display(); });
- th.Start();
- th.Join();
- Display();
- }
- static void Display()
- {
- Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, str);
- }
运行结果:
1 hehe
3 Mgen
可以看到,str静态字段在两个线程中都是独立存储的,互相不会被修改。
2. 使用命名的LocalDataStoreSlot类型
显然ThreadStatic特性只支持静态字段太受限制了。.NET线程类型中的LocalDataStoreSlot提供更好的TLS支持。我们先来看看命名的LocalDataStoreSlot类型,可以通过Thread.AllocateNamedDataSlot来分配一个命名的空间,通过Thread.FreeNamedDataSlot来销毁一个命名的空间。空间数据的获取和设置则通过Thread类型的GetData方法和SetData方法。
- static void Main()
- {
- //创建Slot
- LocalDataStoreSlot slot = Thread.AllocateNamedDataSlot("slot");
- //设置TLS中的值
- Thread.SetData(slot, "hehe");
- //修改TLS的线程
- Thread th = new Thread(() =>
- {
- Thread.SetData(slot, "Mgen");
- Display();
- });
- th.Start();
- th.Join();
- Display();
- //清除Slot
- Thread.FreeNamedDataSlot("slot");
- }
- //显示TLS中Slot值
- static void Display()
- {
- LocalDataStoreSlot dataslot = Thread.GetNamedDataSlot("slot");
- Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(dataslot));
- }
输出:
3 Mgen
1 hehe
3. 使用未命名的LocalDataStoreSlot类型
线程同样支持未命名的LocalDataStoreSlot,未命名的LocalDataStoreSlot不需要手动清除,分配则需要Thread.AllocateDataSlot方法。注意由于未命名的LocalDataStoreSlot没有名称,因此无法使用Thread.GetNamedDataSlot方法,只能在多个线程中引用同一个LocalDataStoreSlot才可以对TLS空间进行操作,将上面的命名的LocalDataStoreSlot代码改成未命名的LocalDataStoreSlot执行:
- //静态LocalDataStoreSlot变量
- static LocalDataStoreSlot slot;
- static void Main()
- {
- //创建Slot
- slot = Thread.AllocateDataSlot();
- //设置TLS中的值
- Thread.SetData(slot, "hehe");
- //修改TLS的线程
- Thread th = new Thread(() =>
- {
- Thread.SetData(slot, "Mgen");
- Display();
- });
- th.Start();
- th.Join();
- Display();
- }
- //显示TLS中Slot值
- static void Display()
- {
- Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(slot));
- }
4. 使用.NET 4.0的ThreadLocal<T>类型
.NET 4.0在线程方面加入了很多东西,其中就包括ThreadLocal<T>类型,他的出现更大的简化了TLS的操作。ThreadLocal<T>类型和Lazy<T>惊人相似,构造函数参数是Func<T>用来创建对象(当然也可以理解成对象的默认值),然后用Value属性来得到或者设置这个对象。ThreadLocal的操作或多或少有点像上面的未命名的LocalDataStoreSlot,但ThreadLocal感觉更简洁更好理解。
- static ThreadLocal<string> local;
- static void Main()
- {
- //创建ThreadLocal并提供默认值
- local = new ThreadLocal<string>(() => "hehe");
- //修改TLS的线程
- Thread th = new Thread(() =>
- {
- local.Value = "Mgen";
- Display();
- });
- th.Start();
- th.Join();
- Display();
- }
- //显示TLS中数据值
- static void Display()
- {
- Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, local.Value);
- }
输出:
3 Mgen
1 hehe
5. 强调一下不同方法和TLS的默认值
上面代码都是一个一个线程设置值,另一个线程直接修改值然后输出,不会觉察到TLS中默认值的状况,下面专门强调一下不同方法的默认值状况。ThreadStatic不提供默认值:
- [ThreadStatic]
- static int i = 123;
- static void Main()
- {
- //输出本地线程TLS数据值
- Console.WriteLine(i);
- //输出另一个线程TLS数据值
- ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(i));
- //控制台等待线程结束
- Console.ReadKey();
- }
输出:
123
0
显然本地线程TLS数据时123,而静态变量的默认值不会在另一个线程中初始化的。
LocalDataStoreSlot很容易可以看出来,不可能有默认值,因为初始化只能构造一个空间,而不能赋予它值,Thread.SetData显然只会在TLS中设置数据,还是用代码演示一下:
- static LocalDataStoreSlot slot = Thread.AllocateDataSlot();
- static void Main()
- {
- Thread.SetData(slot, 123);
- //输出本地线程TLS数据值
- Console.WriteLine(Thread.GetData(slot));
- //输出另一个线程TLS数据值
- ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(Thread.GetData(slot) == null));
- //控制台等待线程结束
- Console.ReadKey();
- }
输出:
123
True
第二行是True,那么另一个线程中的数据是null。
最后重点:.NET 4.0后的ThreadLocal会提供默认值的,还记得我上面说的那句话“ThreadLocal的操作或多或少有点像上面的未命名的LocalDataStoreSlot”?有人可能会问那为什么要创造出ThreadLocal?还有一个很大的区别ThreadLocal可以提供TLS中数据的默认值。(另外还有ThreadLocal是泛型类,而LocalDataStoreSlot不是)。
- static ThreadLocal<int> local = new ThreadLocal<int>(() => 123);
- static void Main()
- {
- //输出本地线程TLS数据值
- Console.WriteLine(local.Value);
- //输出另一个线程TLS数据值
- ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(local.Value));
- //控制台等待线程结束
- Console.ReadKey();
- }
输出:
123
123
这篇文章也可以参考
http://www.cnblogs.com/lulu/archive/2012/03/17/2403872.html
多线程中Local Store Slot(本地存储槽)[转]的更多相关文章
- 多线程中Local Store Slot(本地存储槽)
在Java中有一种ThreadLocal机制,为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突.从线程的角度看,就好像每一个线程都完全 ...
- 与众不同 windows phone (7) - Local Database(本地数据库)
原文:与众不同 windows phone (7) - Local Database(本地数据库) [索引页][源码下载] 与众不同 windows phone (7) - Local Databas ...
- Java Volatile关键字 以及long,double在多线程中的应用
概念: volatile关键字,官方解释:volatile可以保证可见性.顺序性.一致性. 可见性:volatile修饰的对象在加载时会告知JVM,对象在CPU的缓存上对多个线程是同时可见的. 顺序性 ...
- c#初学-多线程中lock用法的经典实例
本文转载自:http://www.cnblogs.com/promise-7/articles/2354077.html 一.Lock定义 lock 关键字可以用来确保代码块完成运行,而不会被 ...
- ubuntu中使用nginx把本地80端口转到其他端口
ubuntu中使用nginx把本地80端口转到其他端口 因为只是在开发的过程中遇到要使用域名的方式访问, 而linux默认把1024以下的端口全部禁用. 在网上找了N多方式开启80端口无果后, 方才想 ...
- Java多线程中易混淆的概念
概述 最近在看<ThinKing In Java>,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在 ...
- 多线程中lock用法的经典实例
多线程中lock用法的经典实例 一.Lock定义 lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.它可以把一段代码定义为互斥段(critical section),互斥段在一 ...
- windows的服务中的登录身份本地系统账户、本地服务账户和网络服务账户修改
以一个redis服务为例: 一个redis注册服务后一般是网络服务账户,但是当系统不存在网络服务账户时,就会导致redis服务无法正常启动.接下来修改redis服务的登录身份. cmd下输入如下命令: ...
- java多线程中的三种特性
java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...
随机推荐
- python3基础盲点
数值类型 Python支持四种不同的数值类型,包括int(整数)long(长整数)float(浮点数)complex (复数) python3对整数的大小不做限制 算数运算符 优先级: 逻辑运算符 优 ...
- Ping隧道
1.研究原因: 校园内网的探索,校内电子图书馆资源的利用,认证校园网 2.目的: 内网服务器:在一台因防火墙等原因仅限icmp数据通过的 公网服务器 : 建立icmp 隧道链接, 并在公网服务器上进 ...
- ADB连接不上手机,端口5037被占用的情况解决
最近在搞手机APP自动化测试,adb连接手机时提示端口被占用 检测5037端口被谁占用,cmd窗口输入命令:netstat -ano | findstr "5037" (注意”50 ...
- Shader Forge学习
最近学习了一下shader forge,一个屌屌哒插件用来生成shader.尽管其降低了制作shader的难度,但是真的想做出满意的shader的话还是得有一定的shader基础.但是仅仅是做出一些简 ...
- PAT - L2-001. 紧急救援( Dijstra )
- PAT - L2-001. 紧急救援 题目链接 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两 ...
- sqlalchemy 转json 的几种常用方式
sqlalchemy 转json 的几种常用方式 # -*- coding:utf-8 -*- import datetime from flask import Flask, json, jsoni ...
- 简析@Resource 和 @Autowired的区别
@Autowird @Autowird 属于spring框架,默认使用类型(byType)进行注入,例如下面代码: @Autowired public IUserService userService ...
- Java简单工厂模式
Java简单工厂模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述简单工厂模式的:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简 ...
- [leetcode-779-K-th Symbol in Grammar]
On the first row, we write a 0. Now in every subsequent row, we look at the previous row and replace ...
- for和foreach的一点总结
两者都是数组的循环遍历,但是区别还是有点: for循环,如果块内有事件操作,那么i是不会等事件操作时候在依次增加,而是一次性走完,,也就是依靠下标定位,下标已经走完了,而foreah是依次增加,它是依 ...