无锁版以时间为GUID的方法

  之前的博客 将时间作为GUID的方法 中,我使用了锁。我在实际的使用中,错将锁的释放放在了if语句中,这纯粹是我的失误,导致了很严重的错误。因此我在想是否有无锁的将时间作为GUID的方式,答案是使用Interlocked中的 CompareExchange方法,该方法是原子操作。说是无锁操作,其实就是让clr来保证操作的原子性,而不用自己写锁。没有锁,也就没有死锁的风险了(当然CLR也可能犯错,但是CLR犯错要比我犯错的概率低太多)。

  我在 将时间作为GUID的方法 中介绍了,DateTime.Now提供不了ms级的时间,虽然时间的最小单位是ms,但是该时间的误差至少在100ms以上,因此当多线程同时调用DateTime.Now.ToString("yyyyMMddHHmmssfff")的时候,如果在100ms内同时并发,就会出现同样的结果,而GUID是不能相同的,因此需要对该方法进行简单的改造,从而保证同一进程内,多线程访问时,时间GUID的唯一性。有了之前死锁的教训,我决定不适用锁来实现。该方法的实现方式是一种乐观并发的模式,《CLR via C#》中多线程部分有介绍。我的想法是,既然DateTime.now有误差,我可以在后面添加一个数字,这个数字每次会+1,这样无论多少个线程访问,都不会重复。代码如下:

static int c = 0; public static string GetTimeUtils() { //这样做无法保证f的唯一性,因为其他线程在调用该方法时,有可能读取了相同的c, //从而f++得到相同结果//return DateTime.Now.ToString("yyyyMMddHHmmssfff") + c++; int f,z; do { f = c; z = f+1; if (z >= 9999) z = 0; } while (Interlocked.CompareExchange(ref c, z, f) != f); return DateTime.Now.ToString("yyyyMMddHHmmssfff") + f; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydxxf.html