TPBzwy 2022-01-21 14:47 采纳率: 0%
浏览 98

concurrentHashSet + ThreadPoolExectuor + RedisTemplate 多线程获取自增ID的问题

问题遇到的现象和发生背景

我定义了一个concurrentHashSet,然后使用线程池开启十个线程并行对redis做1000次incr操作,然后存进set内,最后打印set,结果是redis内部数据没问题,但是打印出来的数量没有1000个。

问题相关代码
/**
 * @author zwy
 * @date 2022/1/20
 */
@RestController
@RequestMapping("/redis")
public class RedisTestController {

    @Resource
    private DefaultRedisService defaultRedisService;

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 10;
    private static final int QUEUE_CAPACITY = 100;
    private static final long KEEP_ALIVE_TIME = 1L;

    @GetMapping("/t1")
    public MultiResponse<Long> incrId() {
        ConcurrentHashSet<Long> concurrentHashSet = new ConcurrentHashSet<>();
        // 消费者线程池
        final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );

        for (int i = 0; i < 1000; i++) {
            threadPoolExecutor.execute(() -> {
//                Long testId = defaultRedisService.incr("test_id");
//                System.out.println("currentThread: " + Thread.currentThread().getName() + " id: " + testId);
//                concurrentHashSet.add(testId);
                concurrentHashSet.add(defaultRedisService.incr("test_id"));
            });
//            concurrentHashSet.add(defaultRedisService.incr("test_id"));
        }

//        threadPoolExecutor.shutdown();
        return MultiResponse.ofWithCollectionSize(concurrentHashSet);
    }

}

RedisService的incr实现

@Override
    public Long incr(Object key) {
        if (isAllStringType(key)) {
            return stringRedisTemplate.opsForValue().increment((String) key);
        }
        return redisTemplate.opsForValue().increment(key);
    }

运行结果及报错内容

img


此外,redis的自增是正常的

我的解答思路和尝试过的方法

开启1000个线程来执行则没问题,但是我的抛弃策略是CallerRunsPolicy,理论来说应该会全部执行才是

我想要达到的结果

结果正常

  • 写回答

2条回答 默认 最新

  • 冷冷的天气 2022-01-22 09:48
    关注

    这个问题很简单,因为子线程确实会执行1000次,ConcurrentHashSet也是线程安全的,并且redis也会进行自增到1000,但是你有没有考虑过主线程不等待子线程执行完成就返回了
    解决方式:1.在返回前sleep一段时间就能看出来
    2.采用CountDownLatch来计数
    一键三连吧

    评论

报告相同问题?

问题事件

  • 修改了问题 1月21日
  • 创建了问题 1月21日

悬赏问题

  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法