关于根据key生成自增ID的实现

有这样一个业务场景,需要根据某个单据号生成5位数自增且不重复id,第一时间想到了使用AtomicInteger来实现,它提供了线程安全的整数操作,它通过利用底层硬件的原子性指令,能够在多线程环境中高效地实现整数的无锁更新,避免了传统同步机制带来的性能开销,在高并发场景下成为计数器可大幅提高程序的执行效率,同时又保证了数据一致性。
代码如下:

  private static final int ID_LENGTH = 5;//定义生成ID的长度
  private static final AtomicInteger nextId = new AtomicInteger(10000);

   public static String generateId() {
       int currentId;
       do {
           currentId = nextId.getAndIncrement();
           if (currentId >= 100000) {
               nextId.set(10000); // 循环使用ID空间
           }
           // 确保ID是5位数,不足前面补0
       } while (!isValidId(String.format("%05d", currentId)));
       return String.format("%05d", currentId);
   }

   private static boolean isValidId(String id) {
       return true;
   }

后面经过实践,发现不能实现我的业务诉求,他只能一直自增生成,越到后面数据量越大,可能数据就会超过5位数,开始思考换一种方式,加入一个key值,遇到不同的key重新从10000开始生成
代码如下:

private static final int ID_LENGTH = 5;
    private static final String PREFIX = "ID:";
    private static final Long ID_EXPIRE = 72 * 60 * 60L;

    private static final AtomicInteger nextId = new AtomicInteger(10000);

    public static String generateId(String decree) {
        int currentId;
        do {
            currentId = nextId.getAndIncrement();
            if (currentId >= 100000) {
                nextId.set(10000); // 循环使用ID空间
            }
            // 确保ID是5位数,不足前面补0
        } while (!isValidId(String.format("%05d", currentId),decree));
        return String.format("%05d", currentId);
    }

    private static boolean isValidId(String id,String decree) {
        //获取redis缓存的List
        List<String> list = CacheUtil.getList(PREFIX+decree);
        //判断当前id是否在list中,在就直接返回false,不在就把当前id存入List并返回true
        if(list.contains(id)){
            return false;
        }
        CacheUtil.setList(PREFIX+decree ,id ,ID_EXPIRE);
        return true;
    }

这样既能够保证数据不会超出5位数的限制又能保证不重复,但是后面使用过程中发现该接口的性能又不太理想,该业务场景下会有大量数据同时来生成ID,每个都要调用该方法,造成Redis访问次数增多,遂放弃使用Redis来存储
最后采用把它存放在本地ConcurrentHashMap中,效率果然大大增加
代码如下:

    private static final ConcurrentHashMap<String, AtomicInteger> lastGeneratedNumbers = new ConcurrentHashMap<>();

    /**
     * 生成一个五位数的自增数字,对于同一个 key,生成的数字不会重复。
     *
     * @param key 参数,用于区分不同的序列
     * @return 五位数的自增数字
     */
    public static synchronized int generateId(String key) {
        // 获取或创建一个 AtomicInteger 对象
        AtomicInteger counter = lastGeneratedNumbers.computeIfAbsent(key, k -> new AtomicInteger(10000));
        // 自增并获取新的值
        int value = counter.incrementAndGet();
        // 检查是否超出五位数的范围
        if (value > 99999) {
            throw new IllegalStateException("The maximum number of unique five-digit numbers has been reached for key: " + key);
        }
        return value;
    }

最后不知道各位是否有更好的方法来实现,欢迎留言

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值