Thread

ThreadLocal引发的灾难

Java

ThreadLocal引发的灾难

在 Java 里有个称之为线程本地变量的类型叫做 ThreadLocal,它与 ThreadLocal 之于 C# 中是一样的作用,可以在线程范围内设置变量,这个变量只会在当前线程可被访问,但是它们有一点不同的是,在 Java 中,当你设置好变量后,在线程使用完毕回到线程池之前,需要手动调用 ThreadLocal.remove() 方法去清除线程本地变量,否则变量随着线程回到线程池,并且在下次使用此线程时此变量继续存在,而在 C# 中,线程回到线程池时会自动清除本地变量,因此无需手动去清除。 我们的业务有这样一个场景:某个业务 UserService 类中,具有多个方法会频繁(甚至循环)调用一个获取用户标签的接口,具体原因是因为某些方法会进行递归,数据结构有个树状结构,因此,为了优化接口响应时间以及看起来不那么蠢,我使用 ThreadLocal 将用户标签接口的返回数据存储到当前线程,因为在单个请求中,多次调用此接口获取数据是不必要的,它看起来像这样: /** * 此静态变量ThreadLocal会为每个线程创建本地副本, 因此USER_TAGS_THREAD_

By FatTiger
All about ExecutionContext and SynchronizationContext

.NET

All about ExecutionContext and SynchronizationContext

前言 这篇文章深入探讨了ExecutionContext和SynchronizationContext, 这是大部分开发人员都不需要了解的 .NET 高级领域. SynchronizationContext 我最早关于 SynchronizationContext 了解可能是在 WindowsForm 程序, 当我错误的在其它线程去更新 UI 控件时, 总会出现一个异常 Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on 翻译过来即 跨线程操作无效:控件从创建它的线程以外的线程访问, 例如这个代码片段: private void button_Click(object sender, EventArgs e) { Task.Run(() => { //异常: 跨线程操作无效:控件从创建它的线程以外的线程访问

By FatTiger
C# Async/Await 最佳实践

C#

C# Async/Await 最佳实践

异步不是魔法,也不需要另一个线程等待 很多不理解异步的人总觉得异步是一种魔法操作,认为使用了异步能够增加程序的处理速度。这是一个常见的误解,异步不是魔法,无法加速你程序的运行速度,如果你的方法以前需要一秒钟返回结果使用异步后一样需要一秒钟返回结果,这些人会觉得奇怪,说好的异步会使程序性能提升呢?另一种常见的误解则是,异步也需要线程来执行,只不过使用了线程池线程,会有一个后台线程继续等待异步结果,但事实总是出乎意料:没有额外线程在等待。 让我们一步步解剖异步的线程无需等待到底是什么,假设我们现在需要对文件进行读取: async Task MyMethodAsync() { //异步读取文件 var text = await System.IO.File.ReadAllTextAsync(@"file.text"); //输出文件内容到控制台 System.Console.WriteLine(text); } 当线程执行到 await System.IO.File.ReadAllTextAsync(@"file.text")时,线程会调用操作系统一

By FatTiger

.NET

ThreadStaticAttribute vs ThreadLocal vs AsyncLocal

前言 在.NET程序里,使用static关键字修饰的变量存在于整个程序的生命周期,这使得它可以被多个线程同时访问,这种方式在某些情况下很好用,但是可能需要加锁来处理线程安全问题,在另一些情况下可能只想在线程内共享变量,多个线程之间的变量互相隔离,这就需要使用ThreadStaticAttribute丶ThreadLocal<T>和AsyncLocal<T> TL;DR 实现方式 跨线程 流向辅助线程 static ✔️ ✔️ AsyncLocal ❌ ✔️ ThreadLocal ❌ ❌ ThreadStaticAttribute ❌ ❌ 流向辅助线程 发生线程上下文切换时,能够保存数据并流向到下一个线程,注意,这是单向数据流,辅助线程上更改数据,并不会影响主线程数据(但是你可以通过引用类型来实现主线程数据的同时更改)。 * 线程上下文切换 * new Thread() * new Task() * Task.Run() * ThreadPool.QueueUserWorkItem() * await

By FatTiger