计算 catch 块中发生的异常数量



我正在尝试收集ConcurrentHashMap中发生的异常的所有计数和异常名称,以便我应该知道此异常发生了多少次。

所以在我的捕获块中,我有地图,它将继续添加异常的名称,并且总计数发生。

下面是我每次出于测试目的which I have modified to always throw SQL Exception的代码,以便我可以看到异常计数是否准确。

所以某些场景——

1(如果我选择线程数作为10,任务数作为50,那么在该映射中,我可以看到该特定字符串的500个异常

2(但是,如果我选择线程数作为40,选择任务数作为500,那么我不会在该地图中看到20000异常,它显示大约19000.

我的问题是为什么?我在这里做错了什么?

class Task implements Runnable {
     public static final AtomicInteger counter_exception = new AtomicInteger(0);
     public static ConcurrentHashMap<String, Integer> exceptionMap = new ConcurrentHashMap<String, Integer>();
     @Override
     public void run() {
     try {
          //Making a db connection and then executing the SQL-
         } catch (SQLException e) {
               exceptionMap.put(e.getCause().toString(), counter_exception.incrementAndGet());
          } catch (Exception e) {
          }
     }
    }

更新:

如果我有这样的东西 - 我得到 40 个线程和 4000 个 taks 的Null Pointer Exception。为什么?

catch (SQLException e) {
synchronized(this) {
                   exceptionMap.put(e.getCause().toString(), counter_exception.incrementAndGet());
}              
}

也许正在发生这样的事情:

任务 1-500:捕获异常,准备调用exceptionMap.put,从传递给所述方法的counter_exception.incrementAndGet()中获取一个号码

任务 500

:具有来自原子整数计数器的编号 500,已计划,以便其exceptionMap.put首先运行

任务 1:具有来自原子整数计数器的数字 1,已计划,以便其exceptionMap.put最后运行

现在,即使计数器是 500 并且我们有 500 个异常,异常消息也会与 1 相关联,因为它是最近执行的。

我觉得这是

错误的方法。

如果您在负载下在应用程序中遇到异常,您应该找到这些异常的原因(或原因(......并修复它们。

计算异常无济于事。 事实上,您可能会通过以下方式使问题变得更糟:

    使你难以
  • 理解你的代码到你添加的额外复杂性,
  • 导致
  • 症状发生变化,使识别导致症状的错误变得更加困难,以及
  • 由于您计算异常的方式错误而引入新的错误。

好的,那么你能做些什么来使问题更容易发现呢?

  • 查看代码库以确保没有压缩异常。
  • 查找不记录异常的异常处理程序。
  • 查找过于宽泛的异常处理程序;例如,ExceptionRuntimeExceptionThrowable
  • 查找过早捕获异常的异常处理程序。 如果你有一个意外的异常,你能做的最好的办法是允许它传播"到顶部"并杀死应用程序或(对于 Web 容器(当前请求。 尝试进行更具体的恢复是一个坏主意......因为你的代码不知道异常意味着什么或是什么导致了它。
  • 最后,确保所有线程都有一个未捕获的异常处理程序......以便至少记录任何未捕获的异常。

如果在应用程序加载时出现异常(尤其是奇怪的异常(,则可能是您的数据结构/对象/变量由两个或多个线程共享并且未正确同步。 我建议您对代码库进行代码审查,以查找此类问题。


更新

查看更新后的代码,NPE 最可能的原因是 e.getCause() 返回null;即您的某些异常没有链式的"原因"异常! 这应该是微不足道的处理;即测试e.getCause()返回的值。

请注意,由于您使用的是 ConcurrentHashMap ,因此不能将null用作键。 这是明确禁止的 - 参见javadoc。

另一个可能的原因是同步不正确。

synchronized(this) {
    exceptionMap.put(e.getCause().toString(), 
                     counter_exception.incrementAndGet());
}

问题是您正在同步this,而执行相同代码的其他线程将具有不同的this...因此,您不会与他们同步。

但是,我很确定您实际上不需要在此处与其他线程同步,因为:

  • 静态变量在类初始化期间初始化,之后(大概(不赋值,并且
  • 对共享对象进行的方法调用是线程安全的。

我会宣布exceptionMapfinal,并摆脱synchronized块。

如果您确实需要同步,您应该在这两个静态对象之一上同步,或者可能在Task.class上同步。

相关内容

  • 没有找到相关文章

最新更新