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

时间:2013-02-08 23:53:57

标签: java atomicity concurrenthashmap

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

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

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

某种情况 -

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

2)但是,如果我选择的线程数为40,任务数量为500,那么我在该地图中看不到20000个例外,它显示{{1} }}。

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

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

2 个答案:

答案 0 :(得分:2)

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

任务1-500:抓住例外,准备拨打exceptionMap.put,从counter_exception.incrementAndGet()获取传递给所述方法的号码

任务500:原子整数计数器中的数字500已被调度,因此其exceptionMap.put先运行

任务1:原子整数计数器中的数字1已被调度,因此其exceptionMap.put最后运行

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

答案 1 :(得分: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