0

我在类中定义了一个 atomicinterger 变量。该类还扩展了线程类。我创建了两个线程并在运行方法中增加原子整数的值。我在运行两个线程后排除了 2 的值,但我得到的值为 1。请让我知道发生了什么下面的代码错误。

public class AtomicIntergerTest extends Thread {

    AtomicInteger i = new AtomicInteger();
    int j = 0;

    @Override
    public void run() {
        i.incrementAndGet();

    }

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub

        AtomicIntergerTest th1 = new AtomicIntergerTest();

        AtomicIntergerTest th2 = new AtomicIntergerTest();

        th1.start();
        th2.start();
        th1.join();
        th2.join();

        System.out.println(th2.i.get());

    }

}
4

2 回答 2

2

因为每个实例AtomicInteger i = new AtomicInteger();创建一个。你自找的AtomicInteger

static AtomicInteger i = new AtomicInteger();
于 2020-10-02T00:57:03.113 回答
0

你说:

如果有一个静态整数,我仍然感到困惑,我可以获得在所有线程中可见的相同数据,我可以实现我的线程安全

你误会了。不,你不能。

虚拟机基本上是这样工作的:

对于任何给定的字段,所有线程都有该字段的本地副本,并且它们都有不公平的硬币。他们在读取或写入时翻转它。如果硬币正面朝上,它们会同步该字段并读/写它。如果硬币落在尾巴上,他们读/写副本。硬币是不公平的,因为它会惹恼你:在测试期间和在你的机器上总是翻转正面,在给重要客户做演示时翻转几次 juuuuust。

因此,如果我们让这段代码在一个线程中运行:

x = x + 1;

和另一个线程中的相同代码,x 可能只增加一次,因为第二个线程读取它的克隆副本,因此错过了第一个线程的增量。或不。也许今天你试了 100 次,结果每次都是 +2。然后你的 winamp 上的下一首歌开始或月相发生变化,现在它似乎可靠地只加了 1。这一切都可能发生,这就是为什么这样的代码从根本上被破坏的原因。您不应该与来自多个线程的字段进行交互,除非您非常注意简化它

除非您建立所谓的先于或后于关系,否则您无法强求硬币。您可以通过使用 volatile 或 synchronized 或调用执行此操作的代码来执行此操作。它变得复杂。迅速地。

AtomicInteger是一个不同的解决方案。它是原子的。如果你有一个线程:

atomicInt.incrementAndGet();

另一个有同样的东西,在他们都跑了之后, atomicInt 已经增加了 2,保证。

于 2020-10-02T01:56:37.667 回答