在Java并发类中,建议我在多线程应用程序中为计数器使用以下代码
private volatile int count;我在问自己,是否可以在包装类Integer而不是基本类型int (参见下面)中使用挥发性关键字:
private volatile Integer count;在这种情况下使用Integer包装器类是否正确?
发布于 2014-06-19 15:13:09
严格地说,这是正确的。如果一个线程设置了一个新的计数,那么每一个读取它的线程都会得到新的值。
如果两个线程同时写入该值,则会遇到问题,因为永远无法保证您上次为计数器读取的值是写入计数器时的值。例如,如果您有两个线程和一个从0开始的计数器。
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。
count = new Integer(count.intValue() + 1);因为JVM仍然需要读取值,所以增加它并写出它,每个值至少是一个周期。
要避免这种情况,可以使用@chrylis建议的AtomicInteger (不需要是易失性的),或者使用同步和/或锁来确保永远不会有2个线程写入计数。
发布于 2014-06-19 15:07:32
实际上,这两个版本的设计都很糟糕。
来自实践中的Java并发性,第39页:
...the
volatile的语义不足以使增量操作(count++)具有原子性,除非您能够保证变量只从单个线程写入。(原子变量确实提供了原子读-修改-写支持,并且经常用作“更好的易失性变量”)
所以我建议使用AtomicInteger
private AtomicInteger count;发布于 2014-06-19 15:00:45
Integer类是不可变的,所以当计数发生变化时,它将获得对一个新Integer的引用,并且挥发性关键字确保新的引用在线程中是可见的。
但是,如果您希望更新是原子的,那么使用AtomicInteger将是一个更好的选择,因为基于当前值的增量否则是不安全的。
https://stackoverflow.com/questions/24309668
复制相似问题