首页 技术 正文
技术 2022年11月15日
0 收藏 948 点赞 4,448 浏览 3169 个字

<!–
#cnblogs_post_body h2,#tinymce h2{background: #54AEDE; border-radius: 15px; border: 2px solid #2D88BF; line-height: 34px; font-size: 28px; color: white; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);padding:5px 0 5px 25px;text-shadow: 0 -1px rgba(0, 0, 0, 0.3);font-family: Consolas,YaHei,微软雅黑;}
–>

关于Identity

Identity自增序列/唯一断标识

起初做这个东西,是在一个内部组件中,用于在高并发的环境下得到一个较短的“相对”不重复标识字符串;(这里说的相对是指一定的数量下不重复)

灵感自然是来自于SqlServer的自增列和@@Identity变量

困扰

但是自从做完之后就有一个问题困扰这我,就是这个Current属性,这个属性的实用性其实非常的差

因为在高并发的环境中,使用Next()之后,即使立即使用Current属性得到的也是一个新的值,这点来说跟SqlServer的@@Identity是完全不同的

@@Identity的值无论并发多严重,你在同一个语句,或者说同一次会话中是不会改变的,除非该次会话新增了记录

(最近用了Oracle的序列对象,其中的sequence.CurrVal和@@Identity是一样的)

由于一直没有好的解决方案,而且没有这个功能不会影响这个类的使用,由于本身简单不需要维护,所以就渐渐遗忘了。

发现

昨日无意间发现了ThreadStaticAttribute这个特性,MSDN官方文档对其的描述是:

用 ThreadStaticAttribute 标记的 static 字段不在线程之间共享。 每个执行线程都有单独的字段实例,并且独立地设置及获取该字段的值。 如果在不同的线程中访问该字段,则该字段将包含不同的值。

看了说明之后,我立即想起了这个被遗忘在角落的对象。逐动手改造

修改代码

using System;namespace blqw
{
/// <summary> 自增序列,最大0xFFFFFFF,超过0xFFFFFFF回归1
/// </summary>
public static class Identity
{
[ThreadStatic]
static int? _ThreadCurrentId; static int _StaticId = ;
/// <summary> 当前值
/// </summary>
public static int Current
{
get { return _ThreadCurrentId.GetValueOrDefault(-); }
}
/// <summary> 当前值的String形式
/// </summary>
public static string CurrentString
{
get
{
if (_ThreadCurrentId.HasValue)
{
return GetString(_ThreadCurrentId.Value);
}
else
{
return null;
}
}
}
/// <summary> 获取一个id,每获取一次就会自增1,该方法在所有线程都是安全的
/// </summary>
public static int Next()
{
int i = System.Threading.Interlocked.Increment(ref _StaticId);
_ThreadCurrentId = i;
if (i > (0xFFFFFFF))
{
i = i - 0xFFFFFFF;
System.Threading.Interlocked.Exchange(ref _StaticId, i);
}
return i;
} //字符字典
static char[] _CharMap = new[]
{
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
}; /// <summary> 获取一个id的String表示形式,每获取一次就会自增1,该方法在所有线程都是安全的
/// </summary>
public static string NextString()
{
int number = Next();
return GetString(number);
} public static string GetString(int number)
{
if (number < )
{
throw new ArgumentOutOfRangeException("number", "number不能小于0");
}
int length = (int)Math.Log(number, ) + ;//52比较合理,不要改了
char[] c = new char[length];
for (int i = length - ; i > ; i--)
{
c[i] = _CharMap[number % ];
number = number / ;
}
c[] = _CharMap[number];
return new string(c);
}
}
}

测试

for (int i = ; i < ; i++)
{
new Thread(o =>
{
Console.WriteLine(o + " > Init: " + Identity.Current);
Thread.Sleep();
Console.WriteLine(o + " > Next: " + Identity.Next());
Thread.Sleep();
Console.WriteLine(o + " > Curr: " + Identity.Current);
Thread.Sleep();
Console.WriteLine(o + " > NStr: " + Identity.NextString());
Thread.Sleep();
Console.WriteLine(o + " > Curr: " + Identity.Current);
}).Start(i);
Thread.Sleep();
}

测试代码比较简单,开10个线程,让他们交错运行就行了

先上一个没有标记StaticThread的结果

ThreadStatic应用(Identity补完)

把StaticThread注释掉运行,可以看到结果 在0号线程中使用Next得到值1 然后使用Current却得到2 ,因为在1号线程中调用Next影响了Current的值

这就是原来的效果,所以之前使用的时候都是 int i = Identity.Next() ;然后就拿 i 使用了

现在加在StaticThread

ThreadStatic应用(Identity补完)

可以看到,现在线程0中的Current属性的值,并不会受到其他线程的影响了

总结

ThreadStatic特性允许我们将一个静态的变量的值在不同线程中是独立的

这个特性在某些情况下还是非常好用的

比如web应用中,每个请求都是一个独立的线程,如果我们希望将一个值作为静态字段全局使用,同时又不想影响其他用户,这时候一般我们是使用Session的

现在就可以有第二种选择了

Session可以将一个值长时间的保存,不于局限一次请求,但是Session需要应用System.Web.dll

ThreadStatic可以直接指定一个静态变量,但仅只能是当前请求,请求总段值就丢了

可以更新需要选择使用

最后,不知道ThreadStatic会不会带来额外的性能问题,希望知道的朋友可以告知

code

https://code.csdn.net/snippets/104950

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,500
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,914
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,747
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,504
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,142
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,306