1

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

因此,在我的 catch 块中,我有一个地图,它将继续添加异常的名称,并且出现总数。

以下是我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) {

          }
     }

    }

更新:

如果我有这样的东西——我会得到Null Pointer Exception40 个线程和 4000 个任务。为什么?

catch (SQLException e) {

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

2 回答 2

2

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

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

任务 500:原子整数计数器的编号为 500,已调度,因此它exceptionMap.put首先运行

任务 1:原子整数计数器的编号为 1,已调度,因此exceptionMap.put最后运行

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

于 2013-02-08T23:59:18.577 回答
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.

于 2013-02-09T02:33:59.980 回答