redis是单线程的,他提供了一个单线程的自增方法increment供我们使用。

现在有一个业务需求,id需要自增生成,且生成速度要求一秒一千以上。废话不多说,直接上代码

public class IncrIdUtils {

    private final String REDIS_KEY_TASK_ID = "AUTO_TASK_ID";

    private final String REDIS_KEY_PRO_INS_ID = "AUTO_PRO_INS_ID";

    @Resource
    private RedisUtils redisUtils;


    @Value("${task.id.last}")
    private Long taskIdLast = 900000000000L;

    @Value("${pro.ins.id.last}")
    private Long proInsIdLast = 900000000000L;

    /**
     * 生成一个长度为12的纯数字字符串作为任务id,规则如下
     * 1.以9开头
     * 2.后11位数字从1开始自增
     *
     * @return 如:"900000000001"
     */
    public String getTaskId() {
        String taskIdRedis;
        long incr = redisUtils.incr(REDIS_KEY_TASK_ID, 1);
        taskIdRedis = String.valueOf(incr + taskIdLast);
        return taskIdRedis;
    }

}

下面是测试代码

@Resource
IncrIdUtils incrIdUtils;
 
public Response testTaskIdCreate(@ApiParam(name = "num", value = "生成数量", required = true) @RequestParam("num") Integer num) throws InterruptedException {
    long start = System.currentTimeMillis();

    Map<String, Integer> dataMap = new ConcurrentHashMap<>();
    ExecutorService executorService = Executors.newFixedThreadPool(100);
    for (int i = 0; i < num; i++) {
        executorService.submit(() -> {
            String taskId = "";
            taskId = incrIdUtils.getTaskId();
            System.out.println(taskId);
            dataMap.put(taskId, 1);
        });
    }
    executorService.shutdown();
    while (true) {
        if (executorService.isTerminated()) {
            Map<String, Integer> resultMap = new HashMap<>();
            resultMap.put("map", dataMap.size());
            resultMap.put("time", (int) (System.currentTimeMillis() - start));
            return Response.success(resultMap);
        }
    }
}
运行代码测试,并发量可以达到每秒一万以上,并且生成的id不会重复,搞定



开发过程中遇到的坑:注意在测试的时候一定不能用hashmap,hashmap是线程不安全的,因为一开始用了hashmap,老师出现数量对不上的情况,换了concurrenthashmap马上好了

用过的其他方法:
在代码中进行自增运算,然后写入的时候用cas算法校验。
  这种方法效率低,增加了redis的读写次数,并且单纯的cas算法并没有保证线程安全,还容易导致内存溢出。再加上synchronized代码锁之后,效率更低,每秒只能生成150个左右。
换成lock锁之后效率更低,只有每秒100个左右。频繁的加锁释放锁也是很浪费时间
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐