首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在包装类中使用易失性关键字

在包装类中使用易失性关键字
EN

Stack Overflow用户
提问于 2014-06-19 14:55:10
回答 4查看 391关注 0票数 3

在Java并发类中,建议我在多线程应用程序中为计数器使用以下代码

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

我在问自己,是否可以在包装类Integer而不是基本类型int (参见下面)中使用挥发性关键字:

代码语言:javascript
复制
private volatile Integer count;

在这种情况下使用Integer包装器类是否正确?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-19 15:13:09

严格地说,这是正确的。如果一个线程设置了一个新的计数,那么每一个读取它的线程都会得到新的值。

如果两个线程同时写入该值,则会遇到问题,因为永远无法保证您上次为计数器读取的值是写入计数器时的值。例如,如果您有两个线程和一个从0开始的计数器。

代码语言:javascript
复制
Thread 1: int temp = count.intValue(); //temp = 0;
Thread 2: int temp = count.intValue(); //temp = 0;
Thread 1: count = new Integer(temp+1); //count = 1;
Thread 2: count = new Integer(temp+1); //count = 1;

如您所见,您增加了两次计数器,但是值只增加了1。

代码语言:javascript
复制
count =  new Integer(count.intValue() + 1);

因为JVM仍然需要读取值,所以增加它并写出它,每个值至少是一个周期。

要避免这种情况,可以使用@chrylis建议的AtomicInteger (不需要是易失性的),或者使用同步和/或锁来确保永远不会有2个线程写入计数。

票数 1
EN

Stack Overflow用户

发布于 2014-06-19 15:07:32

实际上,这两个版本的设计都很糟糕。

来自实践中的Java并发性,第39页:

...the volatile的语义不足以使增量操作(count++)具有原子性,除非您能够保证变量只从单个线程写入。(原子变量确实提供了原子读-修改-写支持,并且经常用作“更好的易失性变量”)

所以我建议使用AtomicInteger

代码语言:javascript
复制
private AtomicInteger count;
票数 4
EN

Stack Overflow用户

发布于 2014-06-19 15:00:45

Integer类是不可变的,所以当计数发生变化时,它将获得对一个新Integer的引用,并且挥发性关键字确保新的引用在线程中是可见的。

但是,如果您希望更新是原子的,那么使用AtomicInteger将是一个更好的选择,因为基于当前值的增量否则是不安全的。

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

https://stackoverflow.com/questions/24309668

复制
相关文章

相似问题

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