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.()是什么:

这意味着:

  • 给我X的最新值,并将其存储在我的私人工作区中
  • 将1添加到存储在我的私人工作区中的值
  • 将我工作区中的内容复制到我复制的内存(可全局访问)
  • 现在,在我们进一步解释这一点之前,我们有一个叫做的过程,这个过程是操作系统在不同线程和进程之间分配处理器时间的过程。这个过程通常为线程提供有限的处理器时间(在windows上大约为40毫秒),然后中断工作,复制处理器寄存器中的所有内容(从而保留其状态)并切换到下一个任务。这就是所谓的

    您无法控制处理何时会被中断并传输到另一个线程

    现在假设有两个线程执行相同的操作:

    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
    线程
    还是4
    for循环
    ?我只想评论一下,这讨论了实现细节。但是,最好关注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