Java 需要澄清的简单多线程代码
我在线程上遇到了这个小问题Java 需要澄清的简单多线程代码,java,c,multithreading,Java,C,Multithreading,我在线程上遇到了这个小问题 int x = 0; add() { x=x+1; } 如果我们在多个线程中运行它,比如说4个线程,那么每次的最终值是x=4,或者可以是1、2、3或4 谢谢 PS 假设加法的原子操作是这样的 LOAD A x ADD A 1 LOAD x A 那么最终结果将是4。我是对的还是错在哪里?这是数据竞争的一个经典例子 现在,让我们仔细看看Addio.()是什么: 这意味着: 给我X的最新值,并将其存储在我的私人工作区中 将1添加到
int x = 0;
add() {
x=x+1;
}
如果我们在多个线程中运行它,比如说4个线程,那么每次的最终值是x=4,或者可以是1、2、3或4
谢谢
PS
假设加法的原子操作是这样的
LOAD A x
ADD A 1
LOAD x A
那么最终结果将是4。我是对的还是错在哪里?这是数据竞争的一个经典例子
现在,让我们仔细看看Addio.()是什么:
这意味着:1. Give me the most recent value of X and store it in my private workspace
2. Add 1 to that value that is stored in my private workspace
3. Copy what I have in my workspace to the memory that I copied from (that is globally accessible).
在它们运行之前,X等于1
第一个线程可能会执行第一条指令,并在其私有工作区中存储在其处理-1时最新的X值。然后发生上下文切换,操作系统中断您的线程,并将控制权交给队列中的下一个任务,该任务恰好是第二个线程。第二个线程还读取X的值,该值等于1
第二个线程设法运行到完成——它在“下载”的值上加1,然后“上传”计算出的值
操作系统再次强制进行上下文切换
现在,第一个线程在中断点继续执行。它仍然会认为最近的值是1,它会将该值增加1,并将其计算结果保存到该内存区域。这就是数据竞争的发生方式。您希望最终结果是3,但它是2
有许多方法可以避免此问题,例如,或。您的代码在两个级别被破坏:
李>
get和increment的原子性未强制执行
解决1。您可以添加volatile
修饰符。这仍然会使操作处于非原子状态。为了确保原子性,您可以(最好)使用AtomicInteger
或synchronized
(包括锁定,而不是首选)
目前,如果从不涉及递增的线程读取,结果可以是0到4之间的任何数字。多线程应用程序是并发的(这就是关键)
A1、A2、A3、A4是本地寄存器
结果是1
,但可能是2
、3
或4
。如果您有另一个线程,它可能会看到由于可视性问题而导致的旧值,并看到0
,我建议您添加一个语言标记以获得更多关注,尽管这似乎是一个一般性问题。您是说4线程
还是4for循环
?我只想评论一下,这讨论了实现细节。但是,最好关注Java语言规范提供的保证(尤其是未提供的保证)。您可以在一个完全不同的体系结构上运行Java,在这个体系结构中,这些要点中的大多数都是无效的。
1. Give me the most recent value of X and store it in my private workspace
2. Add 1 to that value that is stored in my private workspace
3. Copy what I have in my workspace to the memory that I copied from (that is globally accessible).
t1: LOAD A1 x
t2: LOAD A2 x
t3: LOAD A3 x
t4: LOAD A4 x
t1: ADD A1 1
t2: ADD A2 1
t3: ADD A3 1
t4: ADD A4 1
t1: STORE x A1
t2: STORE x A2
t3: STORE x A3
t4: STORE x A4