假设AtomicInteger c
在两个线程(线程1和线程2)之间共享。 Thread1使用t1
设置(仅一次)易失性变量c.incrementAndGet()
。 Thread2使用t2
设置(仅一次)易失变量c.incrementAndGet()
。一旦设置了t1和t2,就不会再由其他任何线程对其进行设置。假设线程1设置了t1
之后,它检查t2
的值并得到null
。是否可以保证随后将t2
设置为比t1
高的值? (反之亦然)。换句话说,下面的断言是否总是正确的?那是为什么呢?
AtomicInteger c = new AtomicInteger();
volatile Integer t1=null;
volatile Integer t2=null;
//Thread1
t1=c.incrementAndGet();
if(t2 == null){
assert t2==null || t2>t1;
}
//Thread2
t2=c.incrementAndGet();
if(t1==null){
assert t1==null || t1>t2;
}
我认为这些断言是正确的,其原因如下:如果为t1分配了c的增量值,并且尚未为t2分配c的增量值,那么当随后为t2分配c的值时,t2必须为大于t1的值。
更新:由于根据断言下面的正确答案可能并不总是成立,因此我添加了第2部分问题:签出Happens before between threads and atomic variable Part 2。
答案 0 :(得分:1)
不,它们并不总是正确的。不能保证线程1将在线程2之前运行,或者操作不会交织。如果它们以以下方式运行:
t2 = 1
if
检查,其结果为true t1 = 2
...然后在步骤3中,线程2将看到t1 != null
和t2 > t1
。
线程1同样可能失败。
(正如JB Nizet所提到的,即使我上面写的操作实际上也包含多个操作。对于这个问题,严格地讲细节级别不是必需的,但是 是真正将事情分解成各自的操作,例如increasAndAndGet和它所涉及的分配。经验可以让您在想显示为什么不起作用的情况下对它们进行过滤,但要表明它将会起作用,您确实需要考虑每个操作。)
答案 1 :(得分:1)
不,不能保证。可能会发生以下情况:
or
的另一个操作数进行求值