Java 生成最大16位唯一数字ID,百万并发不重复

在Java开发中,为解决20位ID在前端失去精度的问题,采用时间戳+AtomicInteger自增数字生成16位ID。然而,这种方法在一万并发时出现超过100个ID重复。为解决此问题,优化策略为截取时间戳、加上随机数和自增数,实现在百万并发下ID无重复,保证ID的唯一性和规律性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在开发过程中,集成了mybatis-plus,数据库在设计过程中,ID主键并没有使用自增的方式来生成,而是采用了它默认的ID生成规则,由于考虑到ID索引查询的问题,因此ID字段设置为数字类型,考虑到业务可能出现的增长,因此ID设置为bigint类型,而Java对应的属性为Long类型。

       但是在实际使用中发现,默认生成的ID基本都是20位长度,由于前端js 最多只能识别16位ID,超过16位ID就会失去精度,起初考虑全局过滤,在返回给前端时将ID转换成string,但是觉得这种方式不太好。所以考虑采用自定义ID生成规则的方式来生成ID,经过几次调试,最终确认采用时间戳+AtomicInteger 自增数字的方式来生成ID,但是在测试的时候发现,在普通的一万多并发的时候,ID重复居然超过100,而且在线上进行数据批量导入的时候,就会出现ID重复的情况,因此经过不断改良,最终修改优化如下:

public class CustomIdGenerator implements IdentifierGenerator{

    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    // 由于JS最多识别16位长度,因此这里控制长度不超过16位,这里控制为16位
    private static int ID_LENGTH = 16;

    @Override
    public Number nextId(Object entity) {
        //  生成最大4位随技术
        int i2 = ThreadLocalRandom.current().nextInt(9999);
        String timeStr = String.valueOf(System.currentTimeMillis());
        // 取出时间串前面相同的部分
        timeStr = timeStr.substring(5);
        // 递增生成最大9999的递增ID
        if (atomicInteger.get() == 9999) {
            atomicInteger.set(0);
        }
        int i1 = atomicInteger.getAndIncrement();
        String id = timeStr.concat(String.valueOf(i2)).concat(i1+"");
        // 严格控制ID长度,如果过长 从最前面截取
        if (id.length() > ID_LENGTH) {
            // 计算多了多少位
            int surplusLenth = id.length() - ID_LENGTH;
            id = id.substring(surplusLenth);
        }
        return Long.valueOf(id);
    }

    public static void main(String[] args) {
        CustomIdGenerator customIdGenerator=new CustomIdGenerator();
        customIdGenerator.nextId(null).longValue();
        final CountDownLatch latch=new CountDownLatch(1000000);
        Set<Long> set=new ConcurrentHashSet<>();
        for(int i=0;i<1000000;i++){
            Thread thread=new Thread(){
                @Override
                public void run() {
                     for(int j=0;j<1;j++){
                         Number number = customIdGenerator.nextId(new Object());
                         long l = number.longValue();
                         boolean add = set.add(l);
                         if(!add) {
                             System.out.println("重复"+l);
                         }
                     }
                    latch.countDown();
                }
            };
            thread.start();
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

采用截取时间戳 + 随机数 + 自增数的方式,来生成ID,经测试在百万并发的情况下,可以做到完全不重复。

 这里为什么要截取时间呢?因为时间的前面部分,基本上都是一样,而且还要占位,在空间有限的情况下,就会大大增加重复率,因此最小限度的去除了前面的相同部分,使得生成的ID 看起来不会乱,后面拼接自增数字,也使得生成的ID看起来更有规律性。

以上便是本人的ID生成方案,各位如有更好的方案可以留言交流。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值