测试代码如下:
private static void TestIdWorker() { HashSet<long> set = new HashSet<long>(); IdWorker idWorker1 = new IdWorker(0, 0); IdWorker idWorker2 = new IdWorker(1, 0); Thread t1 = new Thread(() => DoTestIdWoker(idWorker1, set)); Thread t2 = new Thread(() => DoTestIdWoker(idWorker2, set)); t1.IsBackground = true; t2.IsBackground = true; t1.Start(); t2.Start(); try { Thread.Sleep(30000); t1.Abort(); t2.Abort(); } catch (Exception e) { } Console.WriteLine("done"); } private static void DoTestIdWoker(IdWorker idWorker, HashSet<long> set) { while (true) { long id = idWorker.nextId(); if (!set.Add(id)) { Console.WriteLine("duplicate:" + id); } Thread.Sleep(1); } }snowflake算法可以根据自身项目的需要进行一定的修改 。比如估算未来的数据中心个数,每个数据中心的机器数以及统一毫秒可以能的并发数来调整在算法中所需要的bit数 。
优点:
1)不依赖于数据库,灵活方便,且性能优于数据库 。
2)ID按照时间在单机上是递增的 。
缺点:
1)在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,也许有时候也会出现不是全局递增的情况 。
6、利用zookeeper生成唯一IDzookeeper主要通过其znode数据版本来生成序列号,可以生成32位和64位的数据版本号,客户端可以使用这个版本号来作为唯一的序列号 。很少会使用zookeeper来生成唯一ID 。主要是由于需要依赖zookeeper,并且是多步调用API,如果在竞争较大的情况下,需要考虑使用分布式锁 。因此,性能在高并发的分布式环境下,也不甚理想 。
7、MongoDB的ObjectIdMongoDB的ObjectId和snowflake算法类似 。它设计成轻量型的,不同的机器都能用全局唯一的同种方法方便地生成它 。MongoDB 从一开始就设计用来作为分布式数据库,处理多个节点是一个核心要求 。使其在分片环境中要容易生成得多 。
其格式如下:

文章插图
前4 个字节是从标准纪元开始的时间戳,单位为秒 。时间戳,与随后的5 个字节组合起来,提供了秒级别的唯一性 。由于时间戳在前,这意味着ObjectId 大致会按照插入的顺序排列 。这对于某些方面很有用,如将其作为索引提高效率 。这4 个字节也隐含了文档创建的时间 。绝大多数客户端类库都会公开一个方法从ObjectId 获取这个信息 。接下来的3 字节是所在主机的唯一标识符 。通常是机器主机名的散列值 。这样就可以确保不同主机生成不同的ObjectId,不产生冲突 。为了确保在同一台机器上并发的多个进程产生的ObjectId 是唯一的,接下来的两字节来自产生ObjectId 的进程标识符(PID) 。前9 字节保证了同一秒钟不同机器不同进程产生的ObjectId 是唯一的 。后3 字节就是一个自动增加的计数器,确保相同进程同一秒产生的ObjectId 也是不一样的 。同一秒钟最多允许每个进程拥有2563(16 777 216)个不同的ObjectId 。
推荐阅读
- 在Linux系统上使用ls命令对文件列表进行排序
- JetBrains 2020 年开发者生态系统状况报告,JAVA 最受欢迎的语言
- 日志系统新贵Loki,确实比笨重的ELK轻
- CentOS7下简单搭建Prometheus+Grafana监控系统
- Linux-玩转系统提示符PS1
- Linux系统 交换分区swap的管理
- 这几种常见的“分布式锁”写法,搞懂再也不怕面试官,安排
- Windows 10系统更新又出BUG,据说很多人都中招了,附解决办法
- 提升系统 10 倍web应用性能的 10 个建议
- Win10系统中进入BIOS的详细操作方法
