繁体   English   中英

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

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

这个servlet似乎是从ehCache中从具有此对象的Element中获取一个对象: http : //code.google.com/p/adwhirl/source/browse/src/obj/HitObject.java? repo=servers-mobile

然后继续增加一个原子长的计数器:

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();
    }

这对我来说似乎不是线程安全的,因为可能会从缓存中获取多个线程,如果两个线程同时增加,则可能会失去点击/展示次数。

您是否同意这不是线程安全的?

AtomicLongAtomicInteger在内部使用AtomicLong比较和设置(或比较和交换)。 这个想法是您告诉CAS两件事:您期望long / int拥有的值,以及您想要将其更新为的值。 如果long / int具有您说的应有的值,则CAS将自动进行更新并返回true ;否则,返回true 否则,它将不会进行更新,并且将返回false 许多现代芯片在机器代码级别非常有效地支持CAS。 如果JVM在没有CAS的环境中运行,则可以使用互斥体(Java称为同步)来实现CAS。 无论如何,一旦有了CAS,就可以通过以下逻辑(以伪代码)安全地实现原子增量:

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

如果另一个线程进入并在// 1// 2行之间进行自己的递增,则CAS将失败,并且循环将再次尝试。 否则,CAS将成功。

这种方法有一个赌注:如果争用较低,则CAS的速度要比同步块快,这不太可能导致线程上下文切换。 但是,如果存在很多争用,则某些线程将不得不以每个增量进行多次循环迭代,这显然会浪费工作。 一般来说,在大多数常见负载下,incrementAndGet将更快。

增量是线程安全的,因为AtomicInteger和Family保证了这一点。 但是从缓存中插入和提取存在一个问题,其中可以创建和插入两个(或更多)HitObject。 这可能会导致在首次访问此HitObject时丢失某些匹配。 正如@ denis.solonenko指出的那样,代码中已经有一个TODO可以解决此问题。

但是,我想指出的是,此代码仅在首次访问给定的HitObject时并发。 一旦将HitObject保存在缓存中(并且不再有创建或插入HitObject的线程),那么此代码就完全是线程安全的。 因此,这只是一个非常有限的并发问题,这可能就是他们尚未解决此问题的原因。

暂无
暂无

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

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