Java 线程中未更新原子整数值

Java 线程中未更新原子整数值,java,atomicinteger,Java,Atomicinteger,我在类中定义了一个AtomicIntegrater变量。该类还扩展了thread类。我创建了两个线程,并在run方法中增加了原子整数的值。在运行两个线程后,我将值2排除在外,但得到的值为1。请让我知道以下代码中出现了什么错误 public class AtomicIntergerTest extends Thread { AtomicInteger i = new AtomicInteger(); int j = 0; @Override public voi

我在类中定义了一个AtomicIntegrater变量。该类还扩展了thread类。我创建了两个线程,并在run方法中增加了原子整数的值。在运行两个线程后,我将值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());

    }

}

因为
AtomicInteger i=new AtomicInteger()为每个实例创建一个原子整数。你想要

static AtomicInteger i = new AtomicInteger();

因为
AtomicInteger i=new AtomicInteger()为每个实例创建一个原子整数。你想要

static AtomicInteger i = new AtomicInteger();
你说:

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

你误解了。不,你不能

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

对于任何给定的字段,所有线程都有该字段的本地副本,并且它们都有一个不公平的硬币。他们读或写的时候都会把它翻过来。如果硬币落在磁头上,他们会同步该字段并读/写它。如果硬币落在反面,他们就读/写副本。这枚硬币是不公平的,因为它会给你带来麻烦:在测试期间和在你的机器上总是摇头,在给那个重要的客户演示时总是甩几下尾巴

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

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

除非你建立了所谓的“先到先得”或“后到先得”的关系,否则你不能强迫对方投币。您可以通过使用volatile或synchronized,或者通过调用执行该操作的代码来实现这一点。事情变得复杂了。快点

AtomicInteger
是另一种解决方案。它是原子的。如果您有一个线程,则:

atomicInt.incrementAndGet();
还有一个是相同的,在它们都运行之后,atomicInt已经增加了2,这是有保证的。

你说:

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

你误解了。不,你不能

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

对于任何给定的字段,所有线程都有该字段的本地副本,并且它们都有一个不公平的硬币。他们读或写的时候都会把它翻过来。如果硬币落在磁头上,他们会同步该字段并读/写它。如果硬币落在反面,他们就读/写副本。这枚硬币是不公平的,因为它会给你带来麻烦:在测试期间和在你的机器上总是摇头,在给那个重要的客户演示时总是甩几下尾巴

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

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

除非你建立了所谓的“先到先得”或“后到先得”的关系,否则你不能强迫对方投币。您可以通过使用volatile或synchronized,或者通过调用执行该操作的代码来实现这一点。事情变得复杂了。快点

AtomicInteger
是另一种解决方案。它是原子的。如果您有一个线程,则:

atomicInt.incrementAndGet();

还有一个是相同的,在它们都运行之后,atomicInt已经增加了2,这是有保证的。

非常感谢它工作正常,我仍然不知道是否有一个静态整数,我可以在所有线程中看到相同的数据,这样我就可以实现线程安全,什么是AtomicInteger的合适用例。非常感谢它工作正常,我仍然很困惑,如果有一个静态整数,我可以在所有线程中看到相同的数据,我可以实现线程安全,什么是AtomicInteger的合适用例。我误解了这个概念,在上面的问题中,我用一个静态整数替换了原子整数,并尝试在一个线程中增加它一次,根据我的代码,我尝试了两个线程。我总是得到2的输出。但是当我尝试增加它更大的次数时,例如使用静态整数增加10000次,每次的输出都不同。因此,在这种情况下,原子整数可以保持线程之间的可见性。非常感谢你的评论…我误解了这个概念,在上面的问题中,我用一个静态整数替换了原子整数,并试图在一个线程中增加它一次,根据我的代码,我尝试了两个线程。我总是得到2的输出。但是当我尝试增加更多的次数时,例如10000次使用静态整数,每次的输出都是不同的。因此,在这种情况下,原子整数可以保持线程之间的可见性。非常感谢您的评论。。。