[英]What is difference between int.class and Integer.TYPE in java?
[英]What is the difference between Atomic Integer and Normal immutable Integer class in Java?
由于 Integer 类也是不可变类,我们知道不可变类是线程安全的,这是 Atomic Integer 的需要。 我很困惑 。 是不是不可变对象的读写不需要是原子的,而原子整数的读写是原子的。 这意味着原子类也是线程安全的。
当您需要确保只有一个线程可以更新 int 变量时,AtomicInteger 用于多线程环境。 优点是不需要外部同步,因为修改它的值的操作是以线程安全的方式执行的。
考虑以下代码:
private int count;
public int updateCounter() {
return ++count;
}
如果多个线程调用 updateCounter 方法,它们中的一些可能会收到相同的值。 ++count 操作不是原子操作的原因不仅仅是一个操作,而是由三个操作组成: read count, add 1 to it's value and write it back to it
。 多个调用线程可以看到该变量未修改为其最新值。
上面的代码应该替换为:
private AtomicInteger count = new AtomicInteger(0);
public int updateCounter() {
return count.incrementAndGet();
}
incrementAndGet
方法保证自动递增存储的值并返回它的值,而不使用任何外部同步。
如果你的值永远不会改变,你不必使用 AtomicInteger,使用 int 就足够了。
AtomicInteger 是线程安全的(事实上,java.util.concurrent.atomic 包中的所有类都是线程安全的),而普通整数不是线程安全的。
当您在多线程环境中使用“整数”变量(以使其线程安全)时,您将需要“同步”和“易失性”关键字,而对于原子整数,您不需要“同步”和“易失性”作为原子整数的关键字负责线程安全。
另外,我会推荐以下关于同一主题的有用教程:http: //tutorials.jenkov.com/java-concurrency/compare-and-swap.html
有关“原子”包的更多信息,请参阅下面的 oracle 文档: https ://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html
虽然根据定义,不可变对象是线程安全的,但可变对象也可以是线程安全的。
这正是Atomic...
类( AtomicInteger
、 AtomicBoolean
等)的目的。
各种...get...
和...set...
方法允许对象的线程安全访问和变异。
毫不奇怪,该类是在java.util.concurrent
包中声明的。
您只需浏览java.util.concurrent.atomic
包的API :
一个小的类工具包,支持对单个变量进行无锁线程安全编程。
考虑一个变量
int myInt = 3;
AtomicInteger
与myInt
。
Integer
与3
相关。
换句话说,你的变量是可变的并且可以改变它的值。 而值 3 是一个整数文字,一个常量,一个不可变的表达式。
整数是文字的对象表示,因此是不可变的,您基本上只能读取它们。
AtomicIntegers 是这些值的容器。 您可以阅读和设置它们。 与为变量赋值相同。 但与更改int
变量的值不同,对AtomicInteger
的操作是原子的。
例如,这不是原子的
if(myInt == 3) {
myInt++;
}
这是原子的
AtomicInteger myInt = new AtomicInteger(3);
//atomic
myInt.compareAndSet(3, 4);
我认为 AtomicInteger 和普通不可变 Integer 之间的主要区别将会显现出来,一旦我们了解为什么即使是不可变 Integer 也不是线程安全的。
让我们看一个例子。
假设,我们有一个int count = 5
的值,它被两个名为T1
和T2
的不同线程共享,同时读取和写入。
我们知道,如果有任何值被重新分配给不可变对象,旧对象将保留在池中,而新对象将接管。
现在,当 T1 和 T2 将它们的值更新为 count 变量时,Java 可能会将这个值放入某个缓存中并在那里进行设置操作,我们不知道 JVM 何时会将更新后的值写入主内存,所以可能会有其中一个线程可能会将值更新为完全过时的值。
这将我们带到了volatile关键字。
Volatile - 这个关键字确保对任何变量的所有 I/O 操作都将在主内存上进行,以便所有线程都使用最新的值。
考虑一下,如果 1 个线程正在写入,而其他所有线程都在读取,那么 volatile 将解决我们的问题,但如果所有线程同时在同一个变量上读写,那么我们需要同步以确保线程安全。
volatile 关键字不能确保线程安全。
现在,为什么要使用 AtomicIntegers。 即使使用syncrhonized关键字来保证线程安全,count变量的实际更新操作也将是一个三步过程。
这就是为什么一旦考虑到线程安全,更新普通整数的任何值以更新值需要稍长的时间。
**AtomicIntegers 通过一种称为 Compare-And-Swap(CAS 方法)的优化无锁算法进一步解决了线程安全和更快更新的问题。
它们以单步过程原子方式执行所有更新操作。 **
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.