zoukankan      html  css  js  c++  java
  • 对线程安全理解的例子

    在线用户实体缓存解决方案

       随着网站访问量的增加,在线用户实体信息的存储方式变得重要起来。存储在线用户的信息一般有这三种方案:

         1、用户的实体信息保存在Session里,简单方便,随着Session的过期用户信息自动过期。

         2、用户信息保存在数据库中,用一个表存储在线的用户信息。

         3、用户信息保存在内存。

         当前项目用的是第一种方法,把用户的实体信息保存在Session中,虽然使用方便,但总感觉很别扭。Discuz!NT使用的是第二种方法,把在线用户标识保存在一个表中,从cookie跟读取用户的ID,并从用户信息表查询该用户的信息,组装到实体中。如果有大量的用户在线同时操作时,这也不是一个很好的解决办法。

         这里选择第三种解决方案,把用户信息保存到内存。

         我们使用Dictionary来存储用户信息,由于Dictionary不是线程安全的,因此需要注意只能单线程更新字典。

         先定义一个保存用户信息的实体:

    internal class UserEntity<T>{    /// <summary>    /// 用户信息    /// </summary>    internal T UserInfo { get; set; }    /// <summary>    /// 添加到列表的时间戳    /// </summary>    internal DateTime Timestamp { get; set; }}

         使用泛型包装用户实体,并增加一个时间戳,表示该用户信息添加到内存的时间,过期是根据这个时间来判断的。

         再增加一个在线用户信息管理类:

    /// <summary>/// 在线用户缓存管理/// </summary>/// <typeparam name="T"></typeparam>public class UserCacheManager<T>{    #region 静态属性    /// <summary>    /// 静态用户缓存表    /// </summary>    private static Dictionary<long, UserEntity<T>> _UserList = new Dictionary<long, UserEntity<T>>();    /// <summary>    /// 过期时间    /// </summary>    private static int _ExpiredMinutes = 30;    /// <summary>    /// 定时器    /// </summary>    private static Timer _Timer = null;    #endregion    #region 静态构造函数    /// <summary>    /// 静态构造函数    /// 初始化计时器    /// </summary>    static UserCacheManager()    {        _Timer = new Timer(new TimerCallback(TimerClear), null, 60000, _ExpiredMinutes * 60000);    }    #endregion    #region 私有方法    /// <summary>    /// 清除在线用户    /// </summary>    /// <param name="sender"></param>    private static void TimerClear(object sender)    {        ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncClear));    }    /// <summary>    /// 异步清除过期的在线用户    /// </summary>    /// <param name="sender"></param>    private static void AsyncClear(object sender)    {        //当前时间        DateTime timestamp = DateTime.Now.AddMinutes(0 - _ExpiredMinutes);        //过期的用户列表        var expiredUserList =            (from userEntity in _UserList where userEntity.Value.Timestamp <= timestamp select userEntity);        if (expiredUserList != null && expiredUserList.Count() > 0)        {            List<long> expiredUserIdentities = expiredUserList.Select(o => o.Key).ToList();            lock (_UserList)            {                foreach (long userId in expiredUserIdentities)                    _UserList.Remove(userId);            }        }    }    #endregion    #region 公共方法    /// <summary>    /// 增加在线用户    /// </summary>    /// <param name="userIdentity">用户身份标识</param>    /// <param name="userInfo">用户实体</param>    public static void Add(long userIdentity, T userInfo)    {        lock (_UserList)        {            #region 创建用户实体            UserEntity<T> userEntity = new UserEntity<T>            {                Timestamp = DateTime.Now,                UserInfo = userInfo            };            #endregion            if (_UserList.Keys.Contains(userIdentity))            {                _UserList[userIdentity] = userEntity;            }            else            {                _UserList.Add(userIdentity, userEntity);            }        }    }    /// <summary>    /// 获取用户信息    /// </summary>    /// <param name="userIdentity"></param>    /// <returns></returns>    public static T Get(long userIdentity)    {        lock (_UserList)        {            if (_UserList.Keys.Contains(userIdentity))            {                _UserList[userIdentity].Timestamp = DateTime.Now;                return _UserList[userIdentity].UserInfo;            }            else            {                return default(T);            }        }    }    /// <summary>    /// 移除用户缓存信息    /// </summary>    /// <param name="userIdentity"></param>    public static void Remove(long userIdentity)    {        if (_UserList.Keys.Contains(userIdentity))        {            lock (_UserList)            {                _UserList[userIdentity].Timestamp = DateTime.Now.AddDays(-1);            }        }    }    #endregion}

         Dictionary<long, UserEntity<T>> _UserList用来保存在线的用户列表。

         在静态构造函数中声明了一个定时器,定时器负责清理过期的用户信息。并把清理用户信息的方法装入线程池执行。

         MSDN:只要不修改Dictionary,Dictionary就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若允许多个线程对集合执行读写操作,您必须实现自己的同步。

         所以在更新Dictionary中,都锁定了字典,防止多线程冲突。

         源代码在经过富文本编辑器后显示有点问题,感兴趣的朋友可以  从这里下载源码

         http://blog.moozi.net/archives/onlineusercachemanager/

    http://msdn.microsoft.com/zh-cn/library/c5kehkcz(VS.80).aspx

  • 相关阅读:
    可能用到的两款Linux工具tmux和tpp
    CCF技术动态第68期(云计算专题)...中国云计算发展概况与趋势...
    产生随机数//NULL大写,rand()在cstdlib,不在cmath
    28个Unix/Linux的命令行神器
    oAuth无痛入门指南
    CRM 客户关系管理和云计算...Salesforce企业级云计算的领导者...
    博客终于开通了
    传递与引用
    Java基础概念
    final、finally和finalize(二)
  • 原文地址:https://www.cnblogs.com/chenlulouis/p/1743179.html
Copyright © 2011-2022 走看看