繁体   English   中英

数据在AtomicReference的各个元素上进行竞争

[英]Data Races on individual elements of an AtomicReference

我有一个与通过原子参考访问单个元素有关的问题。 如果我有一个IntegerArray和一个原子引用;是否会通过AtomicReference变量读取和写入数组的各个元素导致数据竞争?

在下面的代码中:num是一个整数数组,其中aRnumbers是数组的原子引用。 在线程1和2中; 我访问aRnumbers.get()[1]并将其递增1。

我可以通过原子引用访问单个元素而无需数据竞争,每次使用22作为两个线程完成后主线程中aRnumbers.get()[1]的输出。

但是,因为原子引用是在数组上定义的,而不是在单个元素上定义的; 在这种情况下不应该有数据竞争导致21/22作为输出?

在这种情况下,没有数据竞争是拥有AtomicIntegerArray数据结构的动机,该结构为每个元素提供单独的AtomicReference吗?

请在下面找到我想要运行的java代码。有人可以告诉我哪里出错了。

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {


    private static int[] num= new int[2];
    private static AtomicReference<int[]> aRnumbers;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MyRun1());
        Thread t2 = new Thread(new MyRun2());

        num[0]=10;
        num[1]=20;

        aRnumbers = new AtomicReference<int[]>(num);

        System.out.println("In Main before:"+aRnumbers.get()[0]+aRnumbers.get()[1]);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("In Main after:"+aRnumbers.get()[0]+aRnumbers.get()[1]);
    }

    static class MyRun1 implements Runnable {
        public void run() {
            System.out.println("In T1 before:"+aRnumbers.get()[1]);
            aRnumbers.get()[1]=aRnumbers.get()[1]+1;

        }
    }

    static class MyRun2 implements Runnable {
        public void run() {
            System.out.println("In T2 before:"+aRnumbers.get()[1]);
            aRnumbers.get()[1]=aRnumbers.get()[1]+1;

        }

    }

}

在这种情况下不应该有数据竞争导致21/22作为输出?

的确有。 你的线程很短暂,很可能它们不会同时运行。

在这种情况下,没有数据竞争是拥有AtomicIntegerArray数据结构的动机,该结构为每个元素提供单独的AtomicReference吗?

是的。

谁能让我知道我哪里出错了。

启动一个线程需要1 - 10毫秒。

即使没有代码被JIT,增加这样的值也可能需要<< 50微秒。 如果它被优化,每增量需要大约50-200纳秒。

由于起步比起操作时间大约20 - 200倍,因此它们不会同时运行,因此没有竞争条件。

尝试将值递增几百万次,因此您有一个竞争条件,因为两个线程同时运行。

增加元素包括三个步骤:

  1. 读取价值。
  2. 增加价值。
  3. 写回价值。

可能发生竞争条件。 举一个例子:线程1读取值(假设为20)。 任务切换。 线程2读取值(再次为20),将其递增并将其写回(21)。 任务切换。 第一个线程递增该值并将其写回(21)。 因此,当进行2次递增操作时,最终值仍然仅增加1。

在这种情况下,数据结构没有帮助。 线程安全集合有助于在并发线程添加,访问和删除元素时保持结构一致。 但是在这里,您需要在增量操作的三个步骤中锁定对元素的访问。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM