首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java.util.concurrent代码评审

java.util.concurrent代码评审
EN

Stack Overflow用户
提问于 2011-02-06 12:31:53
回答 4查看 648关注 0票数 4

我正在学习java.util.concurrent库,并在源代码中找到了许多无限循环,就像这个

代码语言:javascript
复制
//java.util.concurrent.atomic.AtomicInteger by Doug Lea
public final int getAndSet(int newValue) {
    for (;;) {
        int current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

我想知道,在什么情况下,实际值不能等于预期值(在本例中,compareAndSet返回false)?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-02-06 12:37:49

当在另一个线程中修改该值时,get()和compareAndSet()可以看到不同的值。这是并发库需要担心的事情。

票数 3
EN

Stack Overflow用户

发布于 2011-02-06 12:48:30

许多现代CPU都有到原子硬件操作的compareAndSet()映射。这意味着,它是不需要同步的线程安全(相比之下,这是一个相对昂贵的操作)。但是,只有compareAndSet()本身是原子的,因此为了使getAndSet() (即将变量设置为给定的值并返回它当时的值,而不可能在两者之间将变量设置为不同的值),代码使用了一个技巧:首先获取值,然后用它刚得到的值和新的值尝试compareAndSet()。如果失败,变量将被另一个线程操作,然后代码再次尝试。

如果compareAndSet()很少失败,即如果没有太多线程同时写入变量,这比使用同步更快。在任何时候都有许多线程写入变量的极端情况下,同步实际上会更快,因为当存在同步开销时,试图访问变量的其他线程将等待并在轮到它们时被唤醒,而不必重复重试操作。

票数 10
EN

Stack Overflow用户

发布于 2011-02-06 22:46:56

这不是一个无限循环,当处理TAS (test and set)算法时,这是很好的实践。循环所做的是(a)从内存中读取(应该是易失性语义) (b)计算一个新值(c),如果旧值同时没有改变,则写入新值。

在数据库领域,这就是所谓的乐观锁定。它利用了共享内存的大多数并发更新都是无竞争的事实,在这种情况下,这是实现共享内存的最便宜的方法。

事实上,这基本上是一个不偏不倚的锁将做什么,在没有竞争的情况下。它将读取锁的值,如果它被解锁,它将执行线程ID的CAS,如果成功,锁现在被持有。如果它失败了,是别人先弄到锁的。然而,锁以一种复杂得多的方式处理失败案例,而不仅仅是一次又一次地重新尝试op。他们会继续阅读一段时间,以防锁被迅速解锁(自旋锁定),然后通常会去睡觉,让其他线程进入,直到他们的回合(指数后退)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4913292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档