[英]Putting the value in ConcurrentHashMap is atomic or not?
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. 我需要查看
exception is happening
次数exception is happening
如果有)。 I am working with Multithreaded code
, meaning multiple threads will be making connection to database and inserting into database. 我正在使用
Multithreaded code
,这意味着多个线程将连接到数据库并插入数据库。 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
. 因此,我编写了下面的代码,在catch块中,我捕获了异常,并在每次出现异常时都对增加计数进行计数并将其放入
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
. 我的问题是-今天我进行了代码审查,我的一位高级团队成员说,您将不需要在
catch block
的exceptionMap
上synchronized(this)
。 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. 他说
ConurrentHashMap
将为您做到这一点。
So does I will be needing synchronized(this)
block on that exceptionMap
or not.? 那么我是否需要在该
exceptionMap
上使用exceptionMap
synchronized(this)
块? 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 . 如@dnault所述,您还可以使用番石榴的AtomicLongMap 。
UPDATE: some comments on your original: 更新:对您的原件的一些评论:
Task.class
) 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
. ConcurrentHashMap
不允许使用null值,因此如果使用oldValue == null
调用,则replace
将引发异常。 I used this code to increase counter by delta
with returning oldValue
. 我使用此代码通过返回
oldValue
增加计数器的delta
。
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
. 您不必使用
synchronized
块和AtomicInteger
。 You can do it just with ConcurrentHashMap.compute
method which is a thread-safe atomic operation. 您可以使用
ConcurrentHashMap.compute
方法来执行此操作,该方法是线程安全的原子操作。 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;
});
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.