我正在做一个与数据库建立连接的项目。我需要查看exception is happening有多少次。我正在使用Multithreaded code,这意味着多个线程将连接到数据库并插入数据库。因此,在某些时候连接可能会丢失,因此我们需要查看这些异常发生了多少次。

所以我写了下面的代码,在catch块中,我捕捉到异常,并在每次出现异常时都对增加计数,并将其放入ConcurrentHashMap中。

class Task implements Runnable {

     public static final AtomicInteger counter_sql_exception = new AtomicInteger(0);
     public static final AtomicInteger counter_exception = new AtomicInteger(0);
     public static ConcurrentHashMap<String, Integer> exceptionMap = new ConcurrentHashMap<String, Integer>();

     @Override
     public void run() {

     try {

         //Make a db connection and then executing the SQL-

         } catch (SQLException e) {
              synchronized(this) {
                   exceptionMap.put(e.getCause().toString(), counter_sql_exception.incrementAndGet());
              }
              LOG.Error("Log Exception")
          } catch (Exception e) {
              synchronized(this) {
                   exceptionMap.put(e.getCause().toString(), counter_exception.incrementAndGet());
              }
              LOG.Error("Log Exception")
        }
      }
  }

我的问题是-今天,我进行了一次代码审查,我的一位高级团队成员说,您将不需要synchronized(this)exceptionMap上的catch block。我说是的,我们将需要这样做,因为增加计数器是原子的。在 map 中放置一个新值是原子的。但是,在没有同步的情况下进行这两者并不是原子的。他说ConurrentHashMap将为您做到这一点。

那么,是否需要在该synchronized(this)上添加exceptionMap块?如果没有,那为什么呢?如果是,那我应该引用什么原因。

最佳答案

如果您要计算每个异常发生的次数,那么您需要这样的事情:

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

private static void addException(String cause) {
  AtomicInteger count = exceptionMap.get(cause);
  if(count == null) {
    count = new AtomicInteger();
    AtomicInteger curCount = exception.putIfAbsent(cause, count);
    if(curCount != null) {
      count = curCount;
    }
  }
  count.incrementAndGet();
}

请注意,除非定期清除,否则具有静态的异常映射是资源泄漏。

如@dnault所述,您还可以使用guava's AtomicLongMap

更新:对您的原件的一些评论:
  • 是正确的,您确实需要另一个包装同步块(synchronized block),以确保最新值确实进入了 map 。但是,正如@Perception在注释中已经指出的那样,您正在错误的对象实例上进行同步(因为您正在更新静态 map ,所以您需要一个静态实例,例如Task.class)
  • ,但是,您使用的是静态计数器,但是String键对于不同的异常可能会有所不同,因此您实际上并没有在计算每个异常的原因,而是将随机数作为各种映射值放置在

  • 最后,如我的示例所示,
  • 可以解决上述问题,并通过适当使用ConcurrentMap完全丢弃同步块(synchronized block)。
  • 10-01 05:04