gpt4 book ai didi

java - 即使在一个命令中也会出现线程并发问题吗?

转载 作者:行者123 更新时间:2023-12-03 03:14:10 25 4
gpt4 key购买 nike

如果我编译并运行以下(可怕的非同步)Java SE 程序,我对得到的结果感到有点惊讶。

public class ThreadRace {

// this is the main class.

public static void main(String[] args) {

TestRunnable tr=new TestRunnable(); // tr is a Runnable.
Thread one=new Thread(tr,"thread_one");
Thread two=new Thread(tr,"thread_two");

one.start();
two.start(); // starting two threads both with associated object tr.
}
}

class TestRunnable implements Runnable {
int counter=0; // Both threads can see this counter.

public void run() {
for(int x=0;x<1000;x++) {
counter++;
}
// We can't get here until we've added one to counter 1000 times.
// Can we??

System.out.println("This is thread "+
Thread.currentThread().getName()+" and the counter is "+counter);
}
}

如果我在命令行运行“java ThreadRace”,那么这是我的解释发生的事情。创建并启动两个新线程。线程有相同的 Runnable 对象实例 tr,因此它们看到相同的 tr.counter 。两个新线程都向该计数器加 1 1000 次,然后打印该值柜台。

如果我运行很多很多次,那么通常我会得到表单的输出

This is thread thread_one and the counter is 1000
This is thread thread_two and the counter is 2000

偶尔我会得到表单的输出

This is thread thread_one and the counter is 1204
This is thread thread_two and the counter is 2000

请注意,后一种情况发生的情况是 thread_one 完成了向计数器添加 1 1000 次,但 thread_two 已开始添加在 thread_one 打印出计数器的值之前,已经有 1 了。特别是,这个输出对我来说仍然是可以理解的。

但是,偶尔我会得到类似的东西

This is thread thread_one and the counter is 1723
This is thread thread_two and the counter is 1723

据我所知,这种情况“不可能发生”。 System.out.println() 行的唯一方法可以在任一线程中到达,前提是该线程已完成计数到 1000。因此,如果一个线程报告计数器为某些值,我不会感到困扰1000 到 2000 之间的随机数,但我看不出两个线程如何到达其 System.out.println() 行(意味着两个 for 循环都已完成,当然?)并且在打印第二条语句时计数器不是 2000。

两个线程都试图以某种方式精确执行 counter++ 发生了什么同时,一个覆盖另一个?也就是说,一个线程甚至可以是即使在执行单个语句中间也被中断?

最佳答案

“++”运算符不是原子——它不会在一个不间断的循环中发生。可以这样想:

1. Fetch the old value
2. Add one to it
3. Store the new value back

想象一下你得到这个序列:

Thread A: Step 1
Thread B: Step 1
Thread A: Step 2
Thread B: Step 2
Thread A: Step 3
Thread B: Step 3

两个线程都认为它们已经增加了变量,但它的值只增加了 1!第二个“存储回”操作有效地抵消了第一个操作的结果。

现在,事实是,当您添加多个级别的缓存时,实际上可能会发生更奇怪的事情;但这是一个容易理解的解释。您可以通过同步对变量的访问来解决此类问题:整个 run() 方法或使用同步块(synchronized block)的循环内部。正如 Jon 建议的那样,您还可以使用 java.util.concurrent.atomic 中的一些更高级的工具。

关于java - 即使在一个命令中也会出现线程并发问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9087625/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com