【问题标题】:What is the difference between Atomic Integer and Normal immutable Integer class in Java?Java中的Atomic Integer和Normal immutable Integer类有什么区别?
【发布时间】:2016-12-15 06:39:45
【问题描述】:

由于 Integer 类也是不可变类,我们知道不可变类是线程安全的,这就是 Atomic Integer 的需要。 我很迷惑 。 是不是不可变对象的读写不需要是原子的,而原子整数的读写是原子的。 这意味着原子类也是线程安全的。

【问题讨论】:

  • 什么时候使用哪个类??
  • 嗯,一个是可变的,另一个是不可变的。因此,当您需要可变值(存在其他选项)时,可以使用AtomicInteger,而不能使用Integer
  • 当您需要一个线程安全可变值时,您可以使用AtomicInteger,而不仅仅是一个可变值...
  • +1 @EduGR 指定线程安全的可变值。 atomic 包中的类如 AtomicInteger 的工作原理是 volatile 变量在内存中读取/写入以保持多线程环境中的变化。

标签: java multithreading concurrency atomic compare-and-swap


【解决方案1】:

考虑一个变量

int myInt = 3;

AtomicIntegermyInt 相关。

Integer3 相关。

换句话说,你的变量是可变的并且可以改变它的值。而值 3 是一个整数文字、一个常量、一个不可变的表达式。

整数是文字的对象表示,因此是不可变的,您基本上只能读取它们。

AtomicIntegers 是这些值的容器。您可以阅读和设置它们。与为变量赋值相同。但与更改 int 变量的值不同,AtomicInteger 上的操作是原子的。

例如这不是原子的

if(myInt == 3) {
   myInt++; 
}

这是原子的

AtomicInteger myInt = new AtomicInteger(3);

//atomic
myInt.compareAndSet(3, 4);

【讨论】:

  • 虽然这个答案似乎包含了它的一般要点,但 AtomicInteger 不能引用 int 变量,所以你在前 3 行中的示例只是令人困惑。
  • 对不起,我不是母语人士,我的意思不是“java参考”中的参考,而是“牛奶指牛,因为整体指羊”,但也许是“参考”在那种情况下不是正确的词,“相关”会更好吗?
【解决方案2】:

虽然不可变对象根据定义是线程安全的,但可变对象也可以是线程安全的。

这正是Atomic... 类(AtomicIntegerAtomicBoolean 等)的目的。

各种...get......set... 方法允许对象的线程安全访问和变异。

毫不奇怪,该类是在java.util.concurrent 包中声明的。

您只需浏览API 即可获得java.util.concurrent.atomic 包:

支持对单个变量进行无锁线程安全编程的小类工具包。

【讨论】:

  • 我认为原子类应该比不可变包装类有更好的性能
  • @user18424 因为你不能真正将它们用于相同的目的,所以你想错了。没有合乎逻辑的方法来比较这 2 个类之间的性能。
  • @user18424 不是真的。在单线程上下文中,您实际上希望坚持使用Numbers。这完全取决于使用情况。
【解决方案3】:

AtomicInteger 是线程安全的(事实上,java.util.concurrent.atomic 包中的所有类都是线程安全的),而普通整数不是线程安全的。

当您在多线程环境中使用“整数”变量(以使其线程安全)时,您需要“同步”和“易失性”关键字,而对于原子整数,您不需要“同步”和'volatile' 关键字作为原子整数负责线程安全。

另外,我会推荐以下关于同一主题的有用教程: 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

【讨论】:

  • 普通整数只有在与“同步”和“易失”关键字一起使用时才是线程安全的。
  • @developer 整数是不可变的,因此默认情况下是线程安全的,不需要同步或易失性。然而,不变性的缺点是值永远不会改变。如果您需要更改值,请使用 AtomicInteger 或其他方法或 volatile/synchronized 关键字。
【解决方案4】:

当您需要确保只有一个线程可以更新 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 就足够了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 2011-03-26
    • 1970-01-01
    • 2010-11-19
    • 2015-01-29
    • 2012-09-23
    相关资源
    最近更新 更多