首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用易失性变量编写简单的线程安全类?

如何使用易失性变量编写简单的线程安全类?
EN

Stack Overflow用户
提问于 2013-05-03 12:09:06
回答 5查看 4.4K关注 0票数 8

我想编写一个简单的线程安全类,可以用来设置或获取一个整数值。

最简单的方法是使用同步关键字:

代码语言:javascript
复制
public class MyIntegerHolder {

    private Integer value;

    synchronized public Integer getValue() {
        return value;
    }

    synchronized public void setValue(Integer value) {
        this.value = value;
    }

}

我也可以尝试使用易失性

代码语言:javascript
复制
public class MyIntegerHolder {

    private volatile Integer value;

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

}

是具有易失性关键字线程安全的类。

考虑以下事件的顺序:

  1. 线程A将值设置为5。
  2. 线程B将值设置为7。
  3. 线程C读取该值。

根据Java语言规范,

  • "1“发生在"3”之前
  • "2“发生在"3”之前

但我看不出如何从规范中得出"1“发生在"2”之前,因此我怀疑"1“不会在"2”之前发生。

我怀疑线程C可能读取7或5。我认为带有易失性关键字的类不是线程安全的,并且也可以使用以下顺序:

  1. 线程A将值设置为5。
  2. 线程B将值设置为7。
  3. 线程C读取7。
  4. 线程D读5。
  5. 线程C读取7。
  6. 线程D读5。

我是否正确地假设MyIntegerHolder与易失性不是线程安全的?

是否可以使用AtomicInteger制作线程安全的整数保持架:

代码语言:javascript
复制
public class MyIntegerHolder {

    private AtomicInteger atomicInteger = new AtomicInteger();

    public Integer getValue() {
        return atomicInteger.get();
    }

    public void setValue(Integer value) {
        atomicInteger.set(value);
    }

}

下面是实践书中Java并发性的一个片段:

“原子变量的读写具有与易失性变量相同的内存语义。”

编写线程安全MyIntegerHolder的最好方法(最好是非阻塞)是什么?

如果你知道答案,我想知道你为什么认为它是正确的。它符合规格吗?如果是这样的话,是怎么做的?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-05-03 19:15:06

这个问题对我来说并不容易,因为我认为(错误地)了解了发生的一切--在关系之前--使人完全了解了Java模型和易失性的语义。

我在本文中找到了最好的解释:"JSR-133: JavaTM内存模型和线程规范“

上述文件中最相关的部分是"7.3格式良好的处决“一节。

Java内存模型保证程序的所有执行都是格式良好的。执行只有在以下情况下才是正确的。

  • 服从发生在一致性之前
  • 服从同步顺序一致性
  • .(其他一些条件也必须为真)

在一致性之前发生,通常足以得出关于程序行为的结论--但在这种情况下,因为不发生易失性写入--在另一个易失性写入之前就足够了。

MyIntegerHolder与易失性是线程安全的,但它的安全性来自同步顺序的一致性。

在我看来,当线程B即将将值设置为7时,A直到那一刻才通知B它所做的一切(其他答案之一)-它只告诉B易失变量的值。如果线程B所采取的操作是读的而不是写的(在这种情况下,在这两个线程所采取的操作之间的关系之前),线程A将通知B所有事情(将值赋值给其他变量)。

票数 -1
EN

Stack Overflow用户

发布于 2013-05-03 12:15:07

关键字synchronized表示,如果Thread A and Thread B想要访问Integer,它们就不能同时访问。A在告诉B等我做完了再说。

另一方面,volatile使线程更加“友好”。他们开始互相交谈,一起工作来完成任务。所以当B试图访问时,A会告诉B它在那一刻之前所做的一切。B现在知道这些变化,可以从A离开的地方继续其工作。

在Java中,由于这个原因,您有Atomic,它在封面下使用volatile关键字,所以他们做的事情几乎是一样的,但是它们节省了您的时间和精力。

你要找的是AtomicInteger,你说得对。对于您要执行的操作,这是最好的选择。

代码语言:javascript
复制
There are two main uses of `AtomicInteger`:

 * As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently

 * As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms. 

回答您的问题,在一个普通的注意事项

这取决于你需要什么。我并不是说synchronized是错的,volatile是好的,否则很久以前很好的volatile就会移除synchronized。没有绝对的答案,有很多具体的案例和使用场景。

我的几个书签:

并发提示

核心Java并发

Java并发

更新

来自Java并发规范可用的这里

封装java.util.concurrent.atomic 支持对单变量进行无锁线程安全编程的类的小型工具包。

代码语言:javascript
复制
Instances of classes `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, and `AtomicReference` each provide access and updates to a single variable of the corresponding type.
Each class also provides appropriate utility methods for that type.
For example, classes `AtomicLong` and AtomicInteger provide atomic increment methods.

The memory effects for accesses and updates of atomics generally follow the rules for volatiles:

get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.

也是来自这里

Java编程语言volatile关键字:

(在Java的所有版本中)对易失变量的读和写都有全局排序。这意味着每个访问易失性字段的线程将在继续之前读取其当前值,而不是(潜在地)使用缓存的值。(但是,对于易失性读和写与常规读和写的相对顺序没有保证,这意味着它通常不是有用的线程结构。)

票数 4
EN

Stack Overflow用户

发布于 2013-05-03 12:14:30

如果只需要对变量进行get / set,那么就足以像以前那样声明它的易失性。如果您检查AtomicInteger设置/获取工作的方式,您将看到相同的实现

代码语言:javascript
复制
private volatile int value;
...

public final int get() {
    return value;
}

public final void set(int newValue) {
    value = newValue;
}

但你不能这样简单地增加一个易失性的字段。这就是我们使用AtomicInteger.incrementAndGet或getAndIncrement方法的地方。

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

https://stackoverflow.com/questions/16358615

复制
相关文章

相似问题

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