我有以下代码。在windows server 2008中,程序是正确的,并按预期运行。它输出10个不同的id。
然而,当我在windows server 2003中运行它时,程序不正确。它输出10个id,但其中一些id是重复的。似乎锁不工作了。
如果我设置Thread.Sleep(500)
,它在windows server 2003上正常工作。
class Test
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(Util.GetId());
}
Console.ReadLine();
}
}
public class Util
{
private static object idlock = new object();
public static string GetId()
{
string id = "";
lock (idlock)
{
Thread.Sleep(1);
id = System.DateTime.Now.ToString("yyMMddHHmmssffff");
}
return id;
}
}
锁是完全没有必要的;问题是DateTime.Now
的粒度只有~15ms左右(取决于您的系统)。一开始就不要把时间当作身份;您可以简单地这样做:
public static class Util
{
static long _id;
public static string GetId()
{
return Next().ToString("0000000000000000");
}
private static long Next()
{
return Interlocked.Increment(ref _id);
}
}
虽然我建议远离这种生成键的方法,但如果您受到其他条件的限制,那么您可以在不强制等待的情况下修复代码的一种方法是保留对最后生成的id的引用,然后在刚刚生成的id仍然与旧id匹配时,sleep(10)左右。
这将保留代码的所有现有属性,我认为主要的一点是它将在程序运行之间保持递增,而不是像其他示例所示的单个会话。
线程。Sleep的参数是以毫秒为单位的,选择一个更大的数字。或者使用guide . newguid()生成一个真正唯一的ID,而不浪费时间。
DateTime.Ticks
适合你吗?它有100纳秒的分辨率,所以听起来可能有用。在我看来,你也不需要锁定任何东西。
锁定之后,尝试保存先前的值,并比较是否相等。If =,不返回,而是在循环中Sleep然后再试一次。
我个人认为这种方法很糟糕。使用guid,它们是你的朋友。