在WEB程序中小心使用"ThreadStatic"

场景

在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服务器用线程池执行每个请求,多个不同时段执行的请求还是会共享同一个线程。

线程池中的线程是可以被重用的,当你的请求结束后,当前线程结束,这时,其它客户端可能用你上次的线程!

原文地址:https://www.cnblogs.com/longProgrammer/p/3161897.html