简体   繁体   English

这个增量和获取线程安全吗? 看来是从eh快取中拉出物件

[英]Is this incrementAndGet thread-safe? It seems to pull object from eh cache

This servlet seems to fetch an object from ehCache, from an Element which has this object: http://code.google.com/p/adwhirl/source/browse/src/obj/HitObject.java?repo=servers-mobile 这个servlet似乎是从ehCache中从具有此对象的Element中获取一个对象: http : //code.google.com/p/adwhirl/source/browse/src/obj/HitObject.java? repo=servers-mobile

It then goes on to increment the counter which is an atomic long: 然后继续增加一个原子长的计数器:

http://code.google.com/p/adwhirl/source/browse/src/servlet/MetricsServlet.java?repo=servers-mobile#174 http://code.google.com/p/adwhirl/source/browse/src/servlet/MetricsServlet.java?repo=servers-mobile#174

    //Atomically record the hit
    if(i_hitType == AdWhirlUtil.HITTYPE.IMPRESSION.ordinal()) {
        ho.impressions.incrementAndGet();
    }
    else {
        ho.clicks.incrementAndGet();
    }

This doesn't seem thread-safe to me as multiple threads could be fetching from the cache and if both increment at the same time you might loose a click/impression count. 这对我来说似乎不是线程安全的,因为可能会从缓存中获取多个线程,如果两个线程同时增加,则可能会失去点击/展示次数。

Do you agree that this is not thread-safe? 您是否同意这不是线程安全的?

AtomicLong and AtomicInteger use a CAS internally -- compare and set (or compare-and-swap). AtomicLongAtomicInteger在内部使用AtomicLong比较和设置(或比较和交换)。 The idea is that you tell the CAS two things: the value you expect the long/int to have, and the value you want to update it to. 这个想法是您告诉CAS两件事:您期望long / int拥有的值,以及您想要将其更新为的值。 If the long/int has the value you say it should have, the CAS will atomically make the update and return true ; 如果long / int具有您说的应有的值,则CAS将自动进行更新并返回true ;否则,返回true otherwise, it won't make the update, and it'll return false . 否则,它将不会进行更新,并且将返回false Many modern chips support CAS very efficiently at the machine-code level; 许多现代芯片在机器代码级别非常有效地支持CAS。 if the JVM is running in an environment that doesn't have a CAS, it can use mutexes (what Java calls synchronization) to implement the CAS. 如果JVM在没有CAS的环境中运行,则可以使用互斥体(Java称为同步)来实现CAS。 Regardless, once you have a CAS, you can safely implement an atomic increment via this logic (in pseudocode): 无论如何,一旦有了CAS,就可以通过以下逻辑(以伪代码)安全地实现原子增量:

long incrementAndGet(atomicLong, byIncrement)
    do
        oldValue = atomicLong.get()            // 1
        newValue = oldValue + byIncrement
    while ! atomicLong.cas(oldValue, newValue) // 2
    return newValue

If another thread has come in and does its own increment between lines // 1 and // 2 , the CAS will fail and the loop will try again. 如果另一个线程进入并在// 1// 2行之间进行自己的递增,则CAS将失败,并且循环将再次尝试。 Otherwise, the CAS will succeed. 否则,CAS将成功。

There's a gamble in this kind of approach: if there's low contention, a CAS is faster than a synchronized block isn't as likely to cause a thread context switch. 这种方法有一个赌注:如果争用较低,则CAS的速度要比同步块快,这不太可能导致线程上下文切换。 But if there's a lot of contention, some threads are going to have to go through multiple loop iterations per increment, which obviously amounts to wasted work. 但是,如果存在很多争用,则某些线程将不得不以每个增量进行多次循环迭代,这显然会浪费工作。 Generally speaking, the incrementAndGet is going to be faster under most common loads. 一般来说,在大多数常见负载下,incrementAndGet将更快。

The increment is thread safe since AtomicInteger and family guarantee that. 增量是线程安全的,因为AtomicInteger和Family保证了这一点。 But there is a problem with the insertion and fetching from the cache, where two (or more) HitObject could be created and inserted. 但是从缓存中插入和提取存在一个问题,其中可以创建和插入两个(或更多)HitObject。 That would cause potentially losing some hits on the first time this HitObject is accessed. 这可能会导致在首次访问此HitObject时丢失某些匹配。 As @denis.solonenko has pointed, there is already a TODO in the code to fix this. 正如@ denis.solonenko指出的那样,代码中已经有一个TODO可以解决此问题。

However I'd like to point out that this code only suffers from concurrency on first accessing a given HitObject. 但是,我想指出的是,此代码仅在首次访问给定的HitObject时并发。 Once you have the HitObject in the cache (and there are no more threads creating or inserting the HitObject) then this code is perfectly thread-safe. 一旦将HitObject保存在缓存中(并且不再有创建或插入HitObject的线程),那么此代码就完全是线程安全的。 So this is only a very limited concurrency problem, and probably that's the reason they have not yet fixed it. 因此,这只是一个非常有限的并发问题,这可能就是他们尚未解决此问题的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM