I am working on a project in which I am making connections to database. And I need to see how many times an exception is happening
if there are any. I am working with Multithreaded code
, meaning multiple threads will be making connection to database and inserting into database. So it might be possible that at some point connection get lost so we need to see how many times those exception has occurred.
So I wrote a below code and in the catch block, I am catching exception and making a counter to increased every time if there is any exeption and putting it in 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")
}
}
}
My Question is- Today I had a code review and one of my senior team members said, you won't be needing synchronized(this)
on the exceptionMap
in the catch block
. I said yes we will be needing because incrementing the counter is atomic. Putting a new value in the map is atomic. But doing both without synchronization is not atomic . And he said ConurrentHashMap
will be doing this for you.
So does I will be needing synchronized(this)
block on that exceptionMap
or not.? If not then why? And if Yes then what reason should I quote to him.
if you are tying to count the number of times each exception occured, then you need something like this:
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();
}
note that having a static map of exceptions is a resource leak unless you periodically clean it out.
As @dnault mentioned, you could also use guava's AtomicLongMap .
UPDATE: some comments on your original:
Task.class
) And this way should also work.
private static final ConcurrentMap<String, Integer> exceptionMap = new ConcurrentHashMap<String, Integer>();
private static void addException(String cause) {
Integer oldVal, newVal;
do {
oldVal = exceptionMap .get(cause);
newVal = (oldVal == null) ? 1 : (oldVal + 1);
} while (!queryCounts.replace(q, oldVal, newVal));
}
ConcurrentHashMap
doesn't allow null values, so replace
will throw exception if called with oldValue == null
. I used this code to increase counter by delta
with returning oldValue
.
private final ConcurrentMap<Integer,Integer> counters = new ConcurrentHashMap<Integer,Integer>();
private Integer counterAddDeltaAndGet(Integer key, Integer delta) {
Integer oldValue = counters.putIfAbsent(key, delta);
if(oldValue == null) return null;
while(!counters.replace(key, oldValue, oldValue + delta)) {
oldValue = counters.get(key);
}
return oldValue;
}
You don't have to use synchronized
block and AtomicInteger
. You can do it just with ConcurrentHashMap.compute
method which is a thread-safe atomic operation. So your code will look something like this
public class Task implements Runnable {
public static final Map<String, Integer> EXCEPTION_MAP = new ConcurrentHashMap<String, Integer>();
@Override
public void run() {
try {
// Make a db connection and then executing the SQL-
} catch (Exception e) {
EXCEPTION_MAP.compute(e.getCause().toString(), (key, value) -> {
if (value == null) {
return 1;
}
return ++value;
});
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.