likes
comments
collection
share

SpringBoot 中正确使用锁

作者站长头像
站长
· 阅读数 27

错误示范

@GetMapping("/api/tt/{lock}")
public String lockTest4(@PathVariable String lock) {
    synchronized (lock) {
      return "Hello";
    }
}

synchronized关键字的时候,还记得只要是同一把锁就可以锁住,但是在web开发中通常会漏掉框架里的多线程, 你以为锁住了,实质上这段代码是这样的

ExecutorService threadPool = Executors.newFixedThreadPool(1000);
threadPool.execute(() -> {
    xxxController.lockTest4("lockKey");
});

所以这种用法是错误的!

正确示范

private <T> T withLock(String lock, Supplier<T> runnable) {
    String v = null;
    try {
      v = cacheMap.get(lock);
      synchronized (v) {
        return runnable.get();
      }
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
    throw new RuntimeException("请刷新后重试");
}

private static final LoadingCache<String, String> cacheMap = CacheBuilder.newBuilder()
      .initialCapacity(20) // 初识容量
      .maximumSize(500) // 最大容量
      .removalListener(notification -> {
        System.out.println("-----");
        System.out.println(LocalDateTime.now() + " " + notification.getKey() + " " + notification.getValue() + " 被移除,原因:" + notification.getCause());
        System.out.println("-----");
      }).build(new CacheLoader<>() {
        @Override
        public String load(String key) throws Exception {
          System.out.println("load: " + key + " " + LocalDateTime.now());
          return UUID.randomUUID().toString().replaceAll("-", "");
        }
      });
      
@GetMapping("/api/tt/{lock}")
public String lockTest4(@PathVariable String lock) {
    return withLock(lock, () -> {
      return "hello";
    });
}      

更简单的正确用法

synchronized (lock.intern()) {
    ...
}

Stringintern 方法会复用常量池里的对象,所以锁持有的对象是同一个,就不会出现并发操作了。

转载自:https://juejin.cn/post/6985157004616564743
评论
请登录