【.NET深呼吸】存储基于本地线程的值
在特定情况,我们希望这样一个场景:
N个线程同时调用同一个类实例的同一个操作方法,并且同一个变量可以面向每一个线程存储独立的值。比如,某变量X,它对于线程A的值与对于线程B的值是相互独立的。线程A设置了X的值为3,那么只要代码是在线程A上执行的,那么变量X的值就是3;线程B设置X值为7,那么在线程B的代码中X的值就为7。
同样一个X变量,不同的线程访问它就会读写不同的值。
有些时候,我们需要以上功能。只要把希望基于线程本地所使用的值的变量类型声明为ThreadLocal<T>类型即可,其中T表示该变量中要存储的值的数据类型。
下面定义一个类:
public sealed class ThreadingWork
{
private Random m_rand = null;
private ThreadLocal<int> m_localVal = default(ThreadLocal<int>); public ThreadingWork()
{
m_rand = new Random();
m_localVal = new ThreadLocal<int>();
} private void MakeRandom()
{
m_localVal.Value = m_rand.Next(, );
} public void RunOnThreads()
{
// 为变量生成值
MakeRandom();
// 引发事件
string str = $"在线程{Thread.CurrentThread.ManagedThreadId}上设置的值为:{m_localVal.Value}";
ThreadingRuned?.Invoke(this, new RunThreadEventArgs(str));
} public event EventHandler<RunThreadEventArgs> ThreadingRuned; } /// <summary>
/// 自定义事件参数类
/// </summary>
public class RunThreadEventArgs : EventArgs
{
internal RunThreadEventArgs(string s)
{
Value = s;
} public string Value { get; private set; }
}
m_localVal变量是类的字段,它里面存放的是int类型的值。RunOnThreads方法会被不同的线程调用,线程执行方法后,会生成一个随机整数,并存到m_localVal变量中。接着引发ThreadingRuned事件,并将m_localVal变量中存放的值随着事件传递,以便被其他代码使用。
下面,我们测试一下。
// 实例化对象
ThreadingWork work = new ThreadingWork();
// 附加事件处理
work.ThreadingRuned += Work_ThreadingRuned;
// 创建30个Task来干活
for(int n = ; n < ; n++)
{
Thread t = new Thread(work.RunOnThreads);
t.Start();
}
上面代码创建了30个线程,并且线程所执行的都是同一个实例work上的RunOnThreads方法。
当代码运行后,见证奇迹的一刻到了。

从运行结果中可以发现,同一个实例方法被多个线程调用,但m_localVal变量可以存放来自各个线程的值,而每个线程所读取的都是基于当前线程的值,即每个线程读写的值都不同。
尤其是在实现多线程下载的案例中,可以使用同一个实例变量来记录源自不同线程的下载进度(假设每个线程开启一个下载任务)。
【.NET深呼吸】存储基于本地线程的值的更多相关文章
- 3、flask之基于DBUtils实现数据库连接池、本地线程、上下文
本篇导航: 数据库连接池 本地线程 上下文管理 面向对象部分知识点解析 1.子类继承父类__init__的三种方式 class Dog(Animal): #子类 派生类 def __init__(se ...
- flask之基于DBUtils实现数据库连接池、本地线程、上下文
本篇导航: 数据库连接池 本地线程 上下文管理 面向对象部分知识点解析 1.子类继承父类__init__的三种方式 class Dog(Animal): #子类 派生类 def __init__(se ...
- Python 本地线程
1. 本地线程,保证即使是多个线程,自己的值也是互相隔离. 2.普通对象演示 import threading import time class A(): pass a=A() def func(n ...
- 基于本地存储的kvm虚拟机在线迁移
基于本地存储的kvm虚拟机在线迁移 kvm虚拟机迁移分为4种(1)热迁移基于共享存储(2)热迁移基于本地存储(3)冷迁移基于共享存储(4)冷迁移基于本地存储 这里介绍的是基于本地存储的热迁移 动态块迁 ...
- [Swift]LeetCode981. 基于时间的键值存储 | Time Based Key-Value Store
Create a timebased key-value store class TimeMap, that supports two operations. 1. set(string key, s ...
- LeetCode 981.基于时间的键值存储(C++)
创建一个基于时间的键值存储类 TimeMap,它支持下面两个操作: 1. set(string key, string value, int timestamp) 存储键 key.值 value,以及 ...
- ThreadLocal = 本地线程?
一.定义 ThreadLocal是JDK包提供的,从名字来看,ThreadLocal意思就是本地线程的意思. 1.1 是什么? 要想知道他是个啥,我们看看ThreadLocal的源码(基于JDK 1. ...
- Java 类 ThreadLocal 本地线程变量
前言:工作中将要使用ThreadLocal,先学习总结一波.有不对的地方欢迎评论指出. 定义 ThreadLocal并不是一个Thread,而是Thread的局部变量.这些变量不同于它们的普通对应物, ...
- [How to]基于本地镜像的yum镜像源搭建
1.简介 本文介绍如何在封闭环境(无外网)下安装离线安装本地镜像与基于本地镜像的yum镜像源. 2.环境版本交代: OS:CentOS-6.7-x86_64-minimal yum: yum-3.2. ...
随机推荐
- 【oracle】union、union all、intersect、minus 的用法及区别
一.union与union all 首先建两个view create or replace view test_view_1 as as c from dual union as c from dua ...
- nandaom
this python</div><div><br></div><div>hahah</div><div> 来自为知 ...
- tornado 学习笔记17 HTTPServerRequest分析
代表Http请求. 所有的属性都是字符串型. 17.1 属性 (1) method:请求方法类型,比如"GET"."POST" (2) ur ...
- 创建Chrome启动器
今天清理垃圾时不知怎么把chrome启动器删除了,现在要重新创建一个 1.在桌面创建一个chrome.exe的快捷键方式,属性更改目标为: "C:\Program Files (x86)\G ...
- [WPF] 我的WPF自学日记2,自定义入口
在winform中入口文件就是Program.cs,而在WPF中看不到,因为它是自动生成的,可以说隐藏了,我们可以自定义一个入口文件,然后修改项目属性中的启动对象为我们自定义的入口文件. 首先新建入口 ...
- HDU---BigZhuGod的粉丝
Problem Description 真正的粉丝,是不需要题目描述的^_^. Input 第一行输入数据组数T(1≤T≤100).接下来T行,每行一个有格式的字符串,详见样例,字符串长度不超过1 ...
- php中redis的安装
1.当你在使用php时出现下面的问题 2.通过phpinfo()查看php的版本 我的是php5.6版本 3.查看需要下载的redis的版本 4.点击下面的额链接下载redis:http://wind ...
- 验证mongodb主从复制过程~记录操作
接 mongodb的安装:http://www.cnblogs.com/myrunning/p/4319367.html 1.1创建数据目录 在这里我们将不使用mongodb的配置文件启动mongod ...
- Java中@Override的作用
@Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 1.可以当注释用,方便阅读:2.编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错.例如 ...
- PreparedStatement的应用
package it.cast.jdbc; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql ...