Happens before between threads and atomic variable

你离开我真会死。 提交于 2019-12-13 16:07:32

问题


Suppose an AtomicInteger,c, is shared between two threads, thread1 and thread2. Thread1 sets (one time only) a volatile variable t1 using c.incrementAndGet(). Thread2 sets (one time only) a volatile variable t2 using c.incrementAndGet(). Once t1 and t2 are set they are not set again by any other thread. Suppose that after thread1 sets t1, it checks the value of t2 and gets null. Is it guaranteed that t2 is subsequently set to a higher value then t1? (and visa versa). In other words are the assert below always true? Is so why?

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;
}

I believe the asserts are true for the following reason: If t1 is assigned a value from incrementing c and t2 has not yet been assigned a value by incrementing c then when t2 is subsequently assigned a value by incrementing c, it must be greater then the value of t1.

Update: Since as per the correct answer below the asserts may not always hold, I have added a part 2 question: Check out Happens before between threads and atomic variable Part 2.


回答1:


No, there's no guarantee. The following could happen:

  • thread2: c.incrementAndGet (c is 1, and t2 is still null, but will be initialized with 1 later)
  • thread1: c.incrementAndGet (c is 2, and t1 is still null, but will be initialized with 2 later)
  • thread1: t1 = 2
  • thread1: if (t2 == null): the condition is true. The if block is evaluated
  • thread2: t2 = 1
  • thread1: t2 == null: the condition is false, so the other operand of the or is evaluated
  • thread1: t2 > t1: false since t2 is 1 and t1 is 2
  • thread1: assert: fails



回答2:


No, they will not always be true. There is no guarantee that thread 1 will run before thread 2, or that the operations won't interleave. If they run as:

  1. thread 2 assigns t2 = 1
  2. thread 2 does its if check, which evaluates to true
  3. thread 1 assigns t1 = 2
  4. thread 2 does its assert

... then at step 3, thread 2 will see t1 != null and t2 > t1.

Thread 1 can similarly fail.

(As JB Nizet mentions, even the operations I wrote above are actually comprised of multiple operations. That level of detail isn't strictly necessary for this question specifically, but it is a good habit to get into to really break things down into their individual operations, like the incrementAndGet vs the assignment it goes into. Experience will let you filter them out a bit when you want to show why something won't work, but to show that it will work, you really do need to consider each operation.)



来源:https://stackoverflow.com/questions/53363062/happens-before-between-threads-and-atomic-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!