问题
I am trying to collect all the counts of exception happening and the name of exception in a ConcurrentHashMap
so that I should be aware of how many times this exception has occurred.
So in my catch block I have map that will keep on adding the name of exception and there total count occurrence.
Below is my code which I have modified to always throw SQL Exception
everytime for the testing purpose so that I can see the count of exception is accurate or not.
So certain scenario-
1) If I am choosing number of threads as 10
and number of tasks as 50
, then in that map, I can see 500 exception for that particular String
2)But If I am choosing number of threads as 40
and number of tasks as 500
then I am not seeing 20000
exceptions in that map, it shows around 19000
.
My question is why? What wrong I am doing here?
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) {
}
}
}
Updated:
If I have something like this- I am getting Null Pointer Exception
for 40 threads and 4000 taks. Why?
catch (SQLException e) {
synchronized(this) {
exceptionMap.put(e.getCause().toString(), counter_exception.incrementAndGet());
}
}
回答1:
Maybe something like this is happening:
Task 1-500: Catch exceptions, prepare to call exceptionMap.put
, get a number from counter_exception.incrementAndGet()
that is passed to said method
Task 500: Has number 500 from the atomic integer counter, is scheduled so its exceptionMap.put
runs first
Task 1: Has number 1 from the atomic integer counter, is scheduled so its exceptionMap.put
runs last
Now even though the counter is 500 and we had 500 exceptions, the exception message gets associated with 1 because that was executed the most recently.
回答2:
This strikes me as being the wrong approach.
If you are getting exceptions in your application under load, you should be finding the cause (or causes) of those exceptions ... and FIXING them.
Counting the exceptions doesn't help. In fact, that you are likely to make the problem worse by:
- making it hard to understand your code to the extra complexity you are adding,
- causing the symptoms to change, making it harder to identify the bugs that cause them, and
- introducing NEW bugs due to mistakes in the way that you are counting the exceptions.
OK, so what can you do to make the problems easier to find?
- Review your codebase to make sure that you are not squashing exceptions.
- Look for exception handlers that don't log the exception.
- Look for overly broad exception handlers; e.g. for
Exception
orRuntimeException
orThrowable
. - Look for exception handlers that catch exceptions too soon. If you have an unexpected exception, the best thing you can do is to allow it to propagate "to the top" and kill the application or (for a web container) the current request. Trying to do a more specific recover is a bad idea ... 'cos your code doesn't know what the exception means or what caused it.
- Finally, make sure that all threads have an uncaught exception handler ... so that any uncaught exceptions are at least logged.
If you have exceptions appearing when the application is under load (especially bizarre ones) the chances are that you've got data structures / objects / variables that are shared by two or more threads and that are not properly synchronized. I recommend that you do a code review of your codebase looking for this kind of problem.
UPDATE
Looking at your updated code, the most likely cause of your NPE's is that e.getCause()
is returning null
; i.e. some of your exceptions don't have a chained "cause" exception! That should be trivial to deal with; i.e. test the value returned by e.getCause()
.
Note that since you are using ConcurrentHashMap
, you cannot use null
as a key. This is expressly forbidden - see the javadoc.
Another possible cause is incorrect synchronization.
synchronized(this) {
exceptionMap.put(e.getCause().toString(),
counter_exception.incrementAndGet());
}
The problem is that you are synchronizing on this
, and other threads executing the same code will have a different this
... so you won't synchronize with them.
However, I'm pretty sure that you don't actually need to synchronize with other threads here because:
- the static variables are initialized during class initialization and (presumably) not assigned to after that, and
- the method calls you are making on the shared objects are thread-safe.
I would declare exceptionMap
to be final
, and get rid of the synchronized
block.
If you really do need to synchronize, you should be synchronizing on one of those two static objects, or maybe on Task.class
.
来源:https://stackoverflow.com/questions/14783266/counting-the-number-of-exceptions-happening-in-catch-block