Andrzej Czarny

Greenhorn
+ Follow
since Sep 09, 2017
Cows and Likes
Cows
Total received
0
In last 30 days
0
Total given
0
Likes
Total received
0
Received in last 30 days
0
Total given
0
Given in last 30 days
0
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Andrzej Czarny

Hi Scott
I will try to describe it using happens before order.
To simplify lets assume that the main thread will add all 100 Runnables to executor before executor starts executing. We can also assume that it is multi core machine where the main application thread is executed on cpu1 and the executor thread is on cpu2

main thread - cpu1happens before orderexecutor thread - cpu2cpu1  sheepCount1, sheepCount2cpu2  sheepCount1, sheepCount1
service.execute(....)0, 0initial value, initial value
...............
service.execute(....)0, 0initial value, initial value  
Actions in a thread prior to the submission of a Runnable to an Executor happen-before its execution begins0, 00, 0
Thread.sleep(100);sheepCount1.getAndIncrement(); sheepCount2++;0, 01, 1
...............
sheepCount1.getAndIncrement(); sheepCount2++;0, 099, 99
sheepCount1.getAndIncrement(); sheepCount2++;0, 0100, 100
System.out.println(
sheepCount1+" "sheepcount1.get() happens before any other set or updates (Ordering of write and read actions on volatile) we will have 100  100, 99100, 100
+sheepCount2)sheepCount2 has no happens before order100, 99100, 100

The 100 on sheepCount2 does not have to be visible on the main thread (cpu1) as it is executed after getAndIncrement on (cpu2) and the store buffer does not have to be synchronized with other cores caches as it is just plain variable.
To fix the problem all you have to do is to revert the order of Runnable ()-> {sheepCount1.getAndIncrement(); sheepCount2++};
to  ()-> {sheepCount2++; sheepCount1.getAndIncrement()};
Now visibility of sheepCount2++ is guranted by happens before order between writing to sheepCount1 and reading sheepCount1. Or event simpler change sheepCount2 to AtomicInteger.
I will agree that it is very unlike to hit the 99 but still the answer is incorrect as 100, 99 is possible result.

The problem is similar to my puzzle with jcstress where 3 is still possible

result


 Observed state   Occurrences   Expectation  Interpretation                                              
              1   111,112,823    ACCEPTABLE  Actor2 is executed before Actor1                            
              2        33,631    ACCEPTABLE  Actor2 is executed after y = 2 and before x = 3 in Actor1  
              3        26,441     FORBIDDEN  y = 2 can not be reordered with x = 3 as we have volatile...
              6    21,031,593    ACCEPTABLE  Actor2 executed after Actor1                                


to fix it you have to revert y*x to x*y to have happens before order between writing to volatile x and reading it


 Observed state   Occurrences   Expectation  Interpretation                                              
              1   119,613,062    ACCEPTABLE  Actor2 is executed before Actor1                            
              2       134,699    ACCEPTABLE  Actor2 is executed after y = 2 and before x = 3 in Actor1  
              3             0     FORBIDDEN  y = 2 can not be reordered with x = 3 as we have volatile...
              6    32,083,827    ACCEPTABLE  Actor2 executed after Actor1                                



What is your opinion?
Hi,
In my opinion Chapter 7 Question #17 has incorrect answer (according to java memory model).
The Appendix A refers to B (it outputs 100 100) as correct answer. In my opinion C is correct answer (The output cannot be determined ahead of time).
The question has
private static int sheepCount2 =0;
and it is incremented inside newSingleThreadExecutor.
We have 2 threads
T1 - main application thread
T2 - thread from singleThreadExecutor.

There is no happen before relation between T1 and T2 to read the sheepCount2 by T1 after modifications from T2.

Java doc for java.util.concurrent.ExecutorService
"Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task"
this guarantee the visibility of initial value of sheepCount2 inside T2
T2 will modify sheepCount2
We wait 100ms - no impact on data visibility

And T1 will read sheepCount2 - System.out.println(sheepCount2). T1 has no guarantee to have update value from T2 modifications
or rephrasing  T1 will access sheepCount2 without happen before relation with T2.

We need to have a volatile/AtomicInteger on sheepCount or use future with get().
'any actions taken by that task ... happen-before the result is retrieved via Future.get().'