场景
在WEB系统开发中,我们经常面对这样的需求:如何在一个请求中共享数据或对象实例?之前我都会用HttpContext.Current.Items。然而有一天我发现了两个事实:一、每个请求都是在一个线程中执行的;二、[ThreadStatic]可以标注某个静态字段为每个线程提供独立的存储。面对这两个发现,我得出了这个结论:可以用[ThreadStatic]替换HttpContext.Current.Items。
问题
可以用[ThreadStatic]替换HttpContext.Current.Items吗?
实验
实验素材
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Threading; using System.IO; namespace WebThreadStaticStudy { public partial class Test : System.Web.UI.Page { [ThreadStatic] private static DateTime? Now; private static int _Times = 1; protected void Page_Load(object sender, EventArgs e) { if (Now == null) { Now = DateTime.Now; } if (HttpContext.Current.Items["Now"] == null) { HttpContext.Current.Items["Now"] = DateTime.Now; } string content=string.Format("第{0}次,线程:{1},ThreadStatic时间:{2},HttpContext.Current.Items时间:{3}。 " , _Times++ , Thread.CurrentThread.ManagedThreadId , Now , HttpContext.Current.Items["Now"]); this.Response.Write(content); File.AppendAllText(@"F:学习项目规律化学习WebThreadStaticStudyWebThreadStaticStudyLog.txt", content); } } }
实验结果
第1次,线程:8,ThreadStatic时间:2013/5/3 11:22:06,HttpContext.Current.Items时间:2013/5/3 11:22:06。 第2次,线程:10,ThreadStatic时间:2013/5/3 11:22:08,HttpContext.Current.Items时间:2013/5/3 11:22:08。 第3次,线程:8,ThreadStatic时间:2013/5/3 11:22:06,HttpContext.Current.Items时间:2013/5/3 11:22:08。 第4次,线程:10,ThreadStatic时间:2013/5/3 11:22:08,HttpContext.Current.Items时间:2013/5/3 11:22:09。 第5次,线程:11,ThreadStatic时间:2013/5/3 11:22:10,HttpContext.Current.Items时间:2013/5/3 11:22:10。 第6次,线程:10,ThreadStatic时间:2013/5/3 11:22:08,HttpContext.Current.Items时间:2013/5/3 11:22:10。 第7次,线程:8,ThreadStatic时间:2013/5/3 11:22:06,HttpContext.Current.Items时间:2013/5/3 11:22:10。 第8次,线程:11,ThreadStatic时间:2013/5/3 11:22:10,HttpContext.Current.Items时间:2013/5/3 11:22:11。 第9次,线程:8,ThreadStatic时间:2013/5/3 11:22:06,HttpContext.Current.Items时间:2013/5/3 11:22:12。 第10次,线程:11,ThreadStatic时间:2013/5/3 11:22:10,HttpContext.Current.Items时间:2013/5/3 11:22:12。
结论
不可以用[ThreadStatic]替换HttpContext.Current.Items。
原因分析
WEB服务器用线程池执行每个请求,多个不同时段执行的请求还是会共享同一个线程。
线程池中的线程是可以被重用的,当你的请求结束后,当前线程结束,这时,其它客户端可能用你上次的线程!