原子整数值在线程中没有得到更新。

huangapple go评论52阅读模式
英文:

Atomic Integers values are not getting updated in threads

问题

我在类中定义了一个AtomicInteger变量。这个类还继承了Thread类。我创建了两个线程,并在run方法中递增了AtomicInteger的值。我预期在运行两个线程后,AtomicInteger的值应该是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 {
        AtomicIntergerTest th1 = new AtomicIntergerTest();
        AtomicIntergerTest th2 = new AtomicIntergerTest();

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

        System.out.println(th2.i.get());
    }
}
英文:

I have defined an atomicinterger variable in class. The class also extends thread class .I have created two threads and incrementing the value of the atomic integer in run method .I was excepting the value of 2 after running two threads, But I am getting value as 1. Please let me know what went wrong in the below code.

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());

	}

}

答案1

得分: 2

因为 AtomicInteger i = new AtomicInteger(); 每个实例都会创建一个 AtomicInteger。 您想要的是

static AtomicInteger i = new AtomicInteger();
英文:

Because AtomicInteger i = new AtomicInteger(); creates one AtomicInteger per instance. You wanted

static AtomicInteger i = new AtomicInteger();

答案2

得分: 0

你说:

> 我仍然困惑,如果我有一个静态整数,我是否可以在所有线程中获取相同的可见数据,通过这样我可以实现线程安全。

你误解了。不行。

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

对于任何给定的字段,所有线程都有该字段的本地副本,并且它们都有一个不公平的硬币。每当它们读取或写入该字段时,它们会抛掷硬币。如果硬币正面朝上,它们会同步该字段并读取/写入它。如果硬币反面朝上,它们会读取/写入副本。这个硬币是不公平的,它会欺骗你:在测试期间和在你的机器上始终翻转正面,但在向重要客户演示时,会偶尔翻转反面几次。

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

x = x + 1;

并且在另一个线程中有相同的代码,x 只能增加一次,因为第二个线程读取了它的克隆副本,因此错过了第一个线程的增量。或者不是。也许今天你尝试了 100 次,每次数字都增加了 2。然后你的 Winamp 播放器开始下一首歌,或者月亮的相位改变了,现在它似乎只可靠地增加了 1。这一切都可能发生,这就是为什么这样的代码基本上是错误的。除非你已经非常小心地对其进行了优化,否则不应该在多个线程中访问字段。

除非你建立所谓的先于或后于关系,否则你无法强制硬币。你可以通过使用 volatile 或 synchronized 来实现这一点,或者调用执行这些操作的代码。这会变得复杂。迅速地。

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

atomicInt.incrementAndGet();

另一个线程也有相同的代码,在它们都运行完之后,保证 atomicInt 增加了 2。

英文:

You said:

> I am still confused if have have a static integer i can get the same data visible across the all threads with that i can achieve my thread safety

You misunderstand. No you can't.

The VM basically works like this:

For any given field, all threads have a local copy of that field, and they all have an unfair coin. They flip it anytime they read or write to it. If the coin lands heads, they sync the field and read/write it. If the coin lands tails, they read/write the copy. The coin is unfair, in that it will mess with you: Always flip heads during tests and on your machine, flip tails a few times juuuuust when giving a demo to that important customer.

Thus, if we have this code running in one thread:

x = x + 1;

and the same code in another thread, x may only increment once, because the second thread read it's clone copy and thus the first thread's increment is missed. Or not. Maybe today you tried 100 times and the number ended up +2 every time. And then the next song on your winamp starts or the phase of the moon changes and now it seems to reliably add only 1. It can all happen, which is why such code is fundamentally broken. You should not interact with a field from multiple threads unless you've taken great care to streamline it.

You cannot force the coin, unless you establish so-called comes-before or comes-after relationships. You do this by using volatile or synchronized, or by calling code that does that. It gets complicated. Quickly.

AtomicInteger is a different solution. It is, well, atomic. If you have a thread with:

atomicInt.incrementAndGet();

and another one with the same thing, after they've both ran, that atomicInt has been incremented by 2, guaranteed.

huangapple
  • 本文由 发表于 2020年10月2日 08:53:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64164949.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定