Final keyword in java is known to forbid class extension and modification of the fields. It is less known to have special meaning in multithreaded code.
Unfortunately, there is not that much information on the latter, and even most thorough talks avoid deep details on the beauty of finals.
In this talk I apply section 17.5 of java language specification to different examples and show how the spec works. Several myths are busted on the way.
Here's nice article on different aspects of JMM: http://shipilev.net/blog/2014/jmm-pragmatics/
1. Semantics of final fields in java
Vladimir Sitnikov, Valentin Kovalenko
sitnikov@netcracker.com, @VladimirSitnikv
NetCracker
September 2014
2. Introduction
Examples
2 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
3. Why final is required in
JMM?
3 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
4. String safety
String s = ...
if ( checkAccess (s)) {
return readFile (s);
}
Is this a valid security check?
4 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
5. String unsafety in 1.4
String s = ...
if ( checkAccess (s)) {
return readFile (s);
}
The answer depends on the java version, and in java 1.4 the code is
insecure
5 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
6. String unsafety in 1.4
String s = GLOBAL ;
if ( checkAccess (s)) {
return readFile (s);
}
HackThread
GLOBAL =
"/tmp/ etc / passwd "
. substring (4);
For instance: HackThread executes .substring(4) and transfers it
via data race to the checker thread
6 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
7. String unsafety in 1.4
String s = GLOBAL ;
if ( checkAccess (s)) {
return readFile (s);
}
HackThread
GLOBAL =
"/tmp/ etc / passwd "
. substring (4);
In java 1.4 result of substring references the same char array, and
the value depends on String#offset and String#size
7 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
8. String unsafety in 1.4
String s = GLOBAL ;
if ( checkAccess (s)) {
return readFile (s);
}
HackThread
GLOBAL =
"/tmp/ etc / passwd "
. substring (4);
race
race
Since no synchronization is in place, reader might observe
not-fully-initialized String
8 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
9. String unsafety in 1.4
String s = GLOBAL ;
if ( checkAccess (s)) {
return readFile (s);
}
HackThread
GLOBAL =
"/tmp/ etc / passwd "
. substring (4);
race
race
checkAccess might observe "/tmp/etc/passwd", and even then
readFile might observe "/etc/passwd"
9 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
10. String unsafety in 1.4
String s = GLOBAL ;
if ( checkAccess (s)) {
return readFile (s);
}
HackThread
GLOBAL =
"/tmp/ etc / passwd "
. substring (4);
race
race
checkAccess might observe "/tmp/etc/passwd", and even then
readFile might observe "/etc/passwd"
Even synchronization on s and volatile will not help!
10 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
11. String safety in java 1.5+
String s = GLOBAL ;
if ( checkAccess (s)) {
return readFile (s);
}
HackThread
GLOBAL =
"/tmp/ etc / passwd "
. substring (4);
hb
hb
In java 1.5+ final protects from such non-initialized objects from
HackThread
11 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
12. Çà÷åì íàì JMM?
12 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
13. Quiz
int x = 1;
public int neverTryThisAtHome () {
int i = this .x; // it is 1, isn ’t it?
this . setX (2); // just updates x to 2
return this .x - i; // 2 - 1 == ...?
}
What is the result? 1? 0? -1?
13 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
14. Quiz
int x = 1;
public int neverTryThisAtHome () {
int i = this .x; // it is 1, isn ’t it?
this . setX (2); // just updates x to 2
return this .x - i; // 2 - 1 == ...?
}
OK, the result is 1
14 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
15. Quiz
final int x = 1;
public int neverTryThisAtHome () {
int i = this .x; // it is 1, isn ’t it?
this . setX (2); // just updates x to 2
return this .x - i; // 2 - 1 == ...?
}
Let’s add some final
15 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
16. Quiz
final int x = 1;
public int neverTryThisAtHome () {
int i = this .x; // it is 1, isn ’t it?
this . setX (2); // just updates x to 2
return this .x - i; // 2 - 1 == ...?
}
The specification allows all the cases: 1, 0, and even -1! (see also
example 17.5.3-1)
16 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
17. A bit of theory
17 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
18. Program order
I Program order is a total order among inter-thread actions of
each thread in source code order
18 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
19. Program order
I Program order is a total order among inter-thread actions of
each thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations if
observable behavior violates program order
19 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
20. Program order
I Program order is a total order among inter-thread actions of
each thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations if
observable behavior violates program order
I It does not mean the program is executed in program order
20 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
21. Program order
I Program order is a total order among inter-thread actions of
each thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations if
observable behavior violates program order
I It does not mean the program is executed in program order
I For instance: program order is not defined for operations on
local variables
21 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
22. Partial order
I In section 17 JLS "partial order" is mentioned 8 times
22 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
23. Partial order
I In section 17 JLS "partial order" is mentioned 8 times
I Partial order is hb
! a binary relation that is:
23 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
24. Partial order
I In section 17 JLS partial order is mentioned 8 times
I Partial order is hb
! a binary relation that is:
I Reflexive: for each element x, x
hb
! x
24 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
25. Partial order
I In section 17 JLS partial order is mentioned 8 times
I Partial order is hb
! a binary relation that is:
I Reflexive: for each element x, x
hb
! x
I Antisymmetric: if x
hb
! y and y
hb
! x, then x and y are the same
element
25 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
26. Partial order
I In section 17 JLS partial order is mentioned 8 times
I Partial order is hb
! a binary relation that is:
I Reflexive: for each element x, x
hb
! x
I Antisymmetric: if x
hb
! y and y
hb
! x, then x and y are the same
element
I Transitive: if x
hb
! y and y
hb
! z, then x
hb
! z
26 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
27. Happens-before
I General idea of JMM: let’s consider all the executions and forbid
bad ones
27 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
28. Happens-before
I General idea of JMM: let’s consider all the executions and forbid
bad ones
I Happens-before is a partial order that selects allowable reads
28 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
29. Happens-before
I General idea of JMM: let’s consider all the executions and forbid
bad ones
I Happens-before is a partial order that selects allowable reads
I A read either sees the latest write (in hb order)
29 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
30. Happens-before
I General idea of JMM: let’s consider all the executions and forbid
bad ones
I Happens-before is a partial order that selects allowable reads
I A read either sees the latest write (in hb order)
I Or any write via data race when multiple writes are
hb -unordered with the read
30 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
31. Happens-before
I General idea of JMM: let’s consider all the executions and forbid
bad ones
I Happens-before is a partial order that selects allowable reads
I A read either sees the latest write (in hb order)
I Or any write via data race when multiple writes are
hb -unordered with the read
I It must still obey other rules, especially: 17.4.8 executions and
causality requirements
31 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
32. Semantics of final fields
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
I w and r2 – the read and the write in question
32 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
33. Semantics of final fields
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
I w and r2 – the read and the write in question
I f – freeze of a final field, that is read in r1
33 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
34. Semantics of final fields
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
I If the only path from write to read follows all this arrows, then
we must not see earlier writes
34 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
35. Semantics of final fields
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
I If the only path from write to read follows all this arrows, then
we must not see earlier writes
I If multiple paths exist, you need to go deeper
35 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
36. Semantics of final fields
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
I If the only path from write to read follows all this arrows, then
we must not see earlier writes
I If multiple paths exist, you need to go deeper
I We use hb notation to distinguish it from hb and since this
happens-before ordering does not transitively close with other
happens-before orderings 36 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
37. Freeze action w hb
! f hb
! a mc
! r1 dr
! r2
37 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
38. Freeze action w hb
! f hb
! a mc
! r1 dr
! r2
Freeze action
38 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
39. Freeze action w hb
! f hb
! a mc
! r1 dr
! r2
Freeze action
Field
Freezes of a final field occur both at the end of the constructor, and
immediately after each modification
39 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
40. Dereference chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
T local = GLOBAL ; r1
int localX = local .x; r2
I r2 reads a field of an object
40 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
41. Dereference chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
T local = GLOBAL ; r1
int localX = local .x; r2
I r2 reads a field of an object
I Current thread did not create the object
41 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
42. Dereference chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
T local = GLOBAL ; r1
int localX = local .x; r2
I r2 reads a field of an object
I Current thread did not create the object
I Hence, we must read an address of the object somewhere
42 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
43. Dereference chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
T local = GLOBAL ; r1
int localX = local .x; r2
dr
I r2 reads a field of an object
I Current thread did not create the object
I Hence, we must read an address of the object somewhere
I This is called r1 dr
! r2
43 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
44. Dereference chain in two threads w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T localA = new T();
GLOBAL = localA ;
Thread 2
T localB = GLOBAL ; r1
if ( localB != null ) {
int localX = localB .x; r2
}
dr
r1 dr
! r2 (thread 2 reads a field of object created in a foreign thread)
44 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
45. Dereference chain in two threads w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T localA = new T(); a
GLOBAL = localA ;
Thread 2
T localB = GLOBAL ; r1
if ( localB != null ) {
int localX = localB .x; r2
}
dr
dr?
Is there a dr
! r2?
45 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
46. Dereference chain in two threads w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T localA = new T(); a
GLOBAL = localA ;
Thread 2
T localB = GLOBAL ; r1
if ( localB != null ) {
int localX = localB .x; r2
}
dr
dr?
dr does not appear between actions of different threads!
46 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
47. Dereference chain: double-check w hb
! f hb
! a mc
! r1 dr
! r2
T local = GLOBAL ; ra
local = GLOBAL ; rb
int localX = local .x; r2
Is there a dr ?
47 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
48. Dereference chain: double-check w hb
! f hb
! a mc
! r1 dr
! r2
T local = GLOBAL ; ra
local = GLOBAL ; rb
int localX = local .x; r2
dr?
dr?
One of ra dr
! r2 or rb dr
! r2 must exist, however no one can tell
which one
48 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
49. Memory chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T o = new T ();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o;
Thread 3
T o = GL2;
int r = o.x;
mc
If a read sees write, then w1 mc
! r1
49 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
50. Memory chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T o = new T ();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2;
int r = o.x;
mc
mc
If a thread writes the address of an object that was initialized in
another thread, then r1 mc
! w2
50 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
51. Memory chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T o = new T ();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x;
mc
mc
mc
r3 sees w2 ) w2 mc
! r3
51 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
52. Memory chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T o = new T ();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x; r4
mc
mc
mc dr
r3 dr
! r4 (read of a object’s field)
52 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
53. Memory chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T o = new T ();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x; r4
mc
mc
mc dr
mc
r3 dr
! r4 (read of a object’s field) ) r3 mc
! r4
53 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
54. Memory chain: what is that? w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T o = new T ();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x; r4
mc
mc
mc dr
mc
mc
mc is transitive (it is a partial order) ) w1 mc
! r4
54 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
55. Introduction
Examples
55 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
56. Disclaimer
I All the examples contain data races (why bother otherwise?)
56 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
57. Disclaimer
I All the examples contain data races (why bother otherwise?)
I We do not consider cases when null is observed (those cases are
not interesting)
57 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
58. Disclaimer
I All the examples contain data races (why bother otherwise?)
I We do not consider cases when null is observed (those cases are
not interesting)
I Lots of brains were hurt when preparing the slides
58 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
59. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}};
GLOBAL = l;
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r2
}
Can result become 0?
59 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
60. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx;
}
hb
hb
Actions in a thread form happens-before:
w hb
! f , f hb
! a
60 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
61. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ; r0
if (o != null ) {
int result = o.fx;
}
hb
hb
mc
r0 sees write a :
a mc
! r0
61 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
62. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ; r0
if (o != null ) {
int result = o.fx; r1
}
hb
hb
mc
dr
Thread 2 did not create the object, r1 reads its field, and r is the
only read of the address, thus we have dereference chain:
r0 dr
! r1
62 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
63. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ; r0
if (o != null ) {
int result = o.fx; r1
}
hb
hb
mc
dr
mc
r0 dr
! r1 ) r0 mc
! r1
63 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
64. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ; r0
if (o != null ) {
int result = o.fx; r1
}
hb
hb
mc
mc
mc
a mc
! r1 ( mc is transitive)
64 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
65. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r1 r2
}
hb
hb
mc
dr
Let’s pick r2 = r 1, then r1 dr
! r2 ( dr is reflexive)
65 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
66. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r1 r2
}
hb
hb
mc
dr
hb*
Here all the requirements for HB:
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
66 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
67. Trivial final (1) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r1 r2
}
hb
hb
mc
dr
hb*
(w hb
! r2) ) result 2 f42g
67 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
68. Array in a final field (2) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
u [0] = 42; w
fx = u;
}};
GLOBAL = l;
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx;
int result = lfx [0]; r2
}
Can result become 0?
68 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
69. Array in a final field (2) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
u [0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx;
int result = lfx [0]; r2
}
hb
hb
Actions in a thread form happens-before:
w hb
! f , f hb
! a
69 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
70. Array in a final field (2) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
u [0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
r1 sees write a (it reads a regular final field):
a mc
! r1
70 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
71. Array in a final field (2) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
u [0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
Thread 2 did not create array, r2 reads an element of the array, r1 is
the only read of the address of the array, thus dereference chain:
r1 dr
! r2
71 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
72. Array in a final field (2) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
u [0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
hb*
Here are all the requirements for HB:
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
72 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
73. Array in a final field (2) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
u [0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
hb*
(w hb
! r2) ) result 2 f42g
73 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
74. Array reversed (2.1) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
fx = u; // (!)
u [0] = 42; w
}};
GLOBAL = l;
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx;
int result = lfx [0];
}
Can result become 0?
74 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
75. Array reversed (2.1) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
fx = u; // (!)
u [0] = 42; w
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
hb
We compose hb exactly as in the previous example
75 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
76. Array reversed (2.1) w hb
! f hb
! a mc
! r1 dr
! r2
T l = new T() {{
int [] u = new int [1];
fx = u; // (!)
u [0] = 42; w
}}; f
GLOBAL = l; a
T o = GLOBAL ;
if (o != null ) {
int [] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
hb
(w hb
! r2) ) result 2 f42g
The result does not depend on the order of assignment to final fields!
76 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
77. this leaks (3) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this ;
}};
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r2
}
Can result become 0?
77 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
78. this leaks (3) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this ; a
}}; f
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r2
}
hb
hb
Actions in thread form happens-before:
w hb
! f , a hb
! f
78 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
79. this leaks (3) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this ; a
}}; f
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r2
}
hb
hb?
hb
For hb we need f hb
! a!
79 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
80. this leaks (3) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this ; a
}}; f
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r2
}
hb
hb?
hb
If a hb
! f and f hb
! a, thus a = f (anti-symmetry of hb )
However a is cannot be a freeze action!
80 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
81. this leaks (3) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this ; a
}}; f
Thread 2
T o = GLOBAL ;
if (o != null ) {
int result = o.fx; r2
}
hb
hb?
hb
There is no hb , thus all the cases are possible: result 2 f0; 42g
81 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
82. Unintentional this leak (4) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this ;
}};
GLa = l;
Thread 2
T u = GLb;
T o = GLa;
if (o != null ) {
int result = o.fx; r2
}
Can result become 0?
82 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
83. Unintentional this leak (4) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this ; b
}}; f
GLa = l; a
Thread 2
T u = GLb;
T o = GLa;
if (o != null ) {
int result = o.fx;
}
hb
hb
hb?
Actions in a thread form happens-before:
w hb
! f , f hb
! a
83 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
84. Unintentional this leak (4) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this ; b
}}; f
GLa = l; a
Thread 2
T u = GLb;
T o = GLa; ra
if (o != null ) {
int result = o.fx;
}
hb
hb
hb?
mc
Suppose thread 2 sees GLa, thus a mc
! ra!
84 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
85. Unintentional this leak (4) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this ; b
}}; f
GLa = l; a
Thread 2
T u = GLb; rb
T o = GLa; ra
if (o != null ) {
int result = o.fx; r1
}
hb
hb
hb?
mc
dr?
dr?
There should be dr somewhere: rb dr
! r1 or ra dr
! r1
85 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
86. Unintentional this leak (4) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this ; b
}}; f
GLa = l; a
Thread 2
T u = GLb; rb
T o = GLa; ra
if (o != null ) {
int result = o.fx; r1
}
hb
hb
hb?
mc
dr?
dr
! r 1, then we fail, since w hb
If rb dr
! r1 can not be completed
86 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
87. Unintentional this leak (4) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this ; b
}}; f
GLa = l; a
Thread 2
T u = GLb; rb
T o = GLa; ra
if (o != null ) {
int result = o.fx; r1
}
hb
hb
hb?
mc
dr?
dr
Conclusion: if a thread had ever seen object with unfrozen fields,
then there is no final semantics for that object!
87 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
88. Reflection in action (5) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1; w1
}};
GLOBAL = t;
U w = new U ();
w.x = 42; w2
reflectSet (t.fu , w);
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x; r2
}
Can result become 0?
88 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
89. Reflection in action (5) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1;
}};
GLOBAL = t;
U w = new U ();
w.x = 42; w2
reflectSet (t.fu , w);
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x; r2
}
hb*?
We’d better have w2 hb
! r2 (otherwise we must not see the write
of 0 in w.x)
89 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
90. Reflection in action (5) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1;
}};
GLOBAL = t;
U w = new U ();
w.x = 42; w2
reflectSet (t.fu , w); f2
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x; r2
}
hb*?
f2 does not work for hb : there is no suitable f 2 hb
! a
90 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
91. Reflection in action (5) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1;
}}; f1
GLOBAL = t;
U w = new U ();
w.x = 42; w2
reflectSet (t.fu , w); f2
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x; r2
}
hb*?
hb?
f1 does not work for hb as well: it must be w2 hb
! f 1
91 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
92. Reflection in action (5) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1;
}}; f1
GLOBAL = t;
U w = new U ();
w.x = 42; w2
reflectSet (t.fu , w); f2
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x; r2
}
hb*?
hb?
It turns out r2 is not denied to observe 0
92 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
93. Reflection in action (5) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1;
}}; f1
GLOBAL = t; a
U w = new U();
w.x = 42; w2
reflectSet (t.fu , w); f2
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x; r2
}
hb*?
hb?
Conclusion: do not alter the final field after you publish its contents
result 2 f0; 1; 42g
93 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
94. Let’s fix reflection (5.1) w hb
! f hb
! a mc
! r1 dr
! r2
T t = new T() {{
fu = new U ();
fu.x = 1;
}};
U w = new U ();
w.x = 42;
reflectSet (t.fu , w);
GLOBAL = t; a
Thread 2
T t = GLOBAL ;
if (t != null ) {
U u = t.fu;
int result = u.x;
}
If we publish the object after all modifications of final fields, the
publication is safe: result 2 f1; 42g
94 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
95. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a;
Thread 2
A a = GL;
B = new B() {{
fb = o;
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb;
int r = a.fx; r2
Can result become 0?
95 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
96. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
mc
A a = b.fb; rb
int r = a.fx; r1
mc
rb sees wb ) wb mc
! rb
ra sees wa : wa mc
! ra
96 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
97. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
mc
A a = b.fb; rb
int r = a.fx; r1
mc
mc
Thread 2 writes an address of a foreign-created object, thus
ra mc
! wb
97 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
98. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
mc
A a = b.fb; rb
int r = a.fx; r1
mc
mc
dr
Therad 3 did not create object A, r reads its field, and rb is the
only read of A’s address, thus dereference chain:
rb dr
! r1
98 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
99. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
mc
A a = b.fb; rb
int r = a.fx; r1
mc
mc
dr
mc
rb dr
! r1 ) rb mc
! r1
99 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
100. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
mc
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mc
mc
mc is transitive (since it is a partial order) ) wa mc
! r1
100 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
101. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}}; f
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1 r2
mc
dr
Let’s pick r2 = r 1, thus r1 dr
! r2 ( dr is reflexive)
101 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
102. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}}; f
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1 r2
mc
dr
hb
hb
hb*
Here are all the requirements for HB:
w hb
! f hb
! a mc
! r2 ) w hb
! r1 dr
! r2
102 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
103. Final wrapper (6) w hb
! f hb
! a mc
! r1 dr
! r2
Thread 1
A a = new O() {{
fx = 42; w
}}; f
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1 r2
mc
dr
hb
hb
hb*
(w hb
! r2) ) result 2 f42g
103 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
104. Questions?
104 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved