我有一个与通过原子参考访问单个元素相关的问题。 如果我有一个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;
}
}
}
答案 0 :(得分:0)
确实有。你的线程很短暂,很可能它们没有同时运行。在这种情况下不应该有数据竞争导致21/22作为输出吗?
在这种情况下,是否有数据争用的原因是拥有一个AtomicIntegerArray数据结构,为每个元素提供单独的AtomicReference?
是的,是的。
有谁可以让我知道我哪里出错了。
启动一个线程需要1到10毫秒。
即使没有JIT的代码,增加这样的值也可能需要&lt;&lt; 50微秒。如果它被优化,每增量需要大约50-200纳秒。
由于起步时间比他们赢得的操作时间长20到200倍,因此没有竞争条件。
尝试将值递增几百万次,因此您有一个竞争条件,因为两个线程同时运行。
答案 1 :(得分:0)
增加元素包含三个步骤:
可能会出现竞争状况。举一个例子:线程1读取值(假设为20)。任务切换。线程2读取值(再次为20),将其递增并将其写回(21)。任务切换。第一个线程递增该值并将其写回(21)。因此,当进行2次递增操作时,最终值仍然只增加1。
在这种情况下,数据结构没有帮助。线程安全集合有助于在并发线程添加,访问和删除元素时保持结构一致。但是在这里你需要在增量操作的三个步骤中锁定对元素的访问。