实现全局唯一id
符号位:1bit,永远为0
时间戳:31bit,以秒为单位,可以使用69年
序列号:32bit,秒内的计数器,支持每秒产生2^32个不同ID
代码实现:
每天一个key防止重复
使用位运算拼接
@Component
public class RedisIdWorker {
private static final long BEGIN_TIMESTAMP = 1640995200L;
private static final int COUNT_BITS = 32;
@Resource
private StringRedisTemplate stringRedisTemplate;
public long nextId(String keyPrefix) {
// 1、生成时间戳
long nowSecond = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
// 2、生成序列号
// 2.1 获取当前日期 精确到日
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
// 2.2 生成自增长
long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
// 3、拼接并返回
return timestamp << COUNT_BITS | count;
}
用Test测试一下
private ExecutorService es = Executors.newFixedThreadPool(500);
@Test
public void testIdWorker() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(300);
Runnable task = () -> {
for (int i = 0; i < 100; i++) {
long id = redisIdWorker.nextId("order");
System.out.println("id = " + id);
}
latch.countDown();
};
long begin = System.currentTimeMillis();
for (int i = 0; i < 300; i++) {
es.submit(task);
}
latch.await();
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - begin) + "ms");
}
300个线程每个生成100个 测试结果
id = 317595466986452266
.......
id = 317595466986452265
id = 317595466986452269
id = 317595466986452267
id = 317595466986452268
id = 317595466986452270
id = 317595466986452271
id = 317595466986452272
耗时:1987ms
其他的全局唯一id生成策略
还可以使用UUID,雪花算法 和数据库自增