Date post: | 21-May-2015 |
Category: |
Software |
Upload: | vladimir-sitnikov |
View: | 191 times |
Download: | 1 times |
Семантика final полей в java
Владимир Ситников, Валентин Коваленко[email protected], @VladimirSitnikv
NetCracker
Сентябрь 2014
Введение
Примеры
2 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Зачем final в JMM?
3 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Безопасность String
String s = ...
if (checkAccess(s)) {
return readFile(s);
}
Правильно ли проверяются права на доступ к файлу?
4 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Без опасность String в java 1.4
String s = ...
if (checkAccess(s)) {
return readFile(s);
}
Ответ зависит от версии, и в java 1.4 возможны проблемы
5 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Без опасность String в java 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
Например: HackThread выполняет .substring(4) и коварнопередаёт его в поток, читающий файлы
6 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Без опасность String в java 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
В java 1.4 substring-строка ссылается на тот же массивсимволов, и всё опреледяется полями String#offset и String#size
7 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Без опасность String в java 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
race
race
Синхронизации между потоками нет, поэтому читатель можетувидеть недоинициализированный объект-строку
8 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Без опасность String в java 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
race
race
checkAccess может увидеть "/tmp/etc/passwd", а readFile уже"/etc/passwd"
Даже синхронизация на s и volatile не спасут!
9 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Без опасность String в java 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
race
race
checkAccess может увидеть "/tmp/etc/passwd", а readFile уже"/etc/passwd"Даже синхронизация на s и volatile не спасут!
10 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Безопасность String в java 1.5+
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
hb
hb
В java 1.5+ final защищает от недосозданных объектов иHackTread
11 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Зачем нам JMM?
12 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Код-загадка
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 == ...?
}
Какие значения могут вернуться? 1? 0? -1?
13 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Код-загадка
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 == ...?
}
Да, тут вернётся 1
14 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Код-загадка
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 == ...?
}
А теперь добавим ножек final
15 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Код-загадка
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 == ...?
}
Спецификация разрешает все варианты: 1, 0, и даже -1! (см.пример 17.5.3-1)
16 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Немного теории
17 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Программный порядок (program order)
I Отражает то, в каком порядке написан исходный код
I Компилятору запрещено переупорядочивать, игнорировать именять операции, если это нарушит program order
I Но это не значит, что всё выполняется именно так, как висходном коде
I Например: для операций над локальными переменнымиprogram order вообще не определён
18 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Программный порядок (program order)
I Отражает то, в каком порядке написан исходный кодI Компилятору запрещено переупорядочивать, игнорировать именять операции, если это нарушит program order
I Но это не значит, что всё выполняется именно так, как висходном коде
I Например: для операций над локальными переменнымиprogram order вообще не определён
19 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Программный порядок (program order)
I Отражает то, в каком порядке написан исходный кодI Компилятору запрещено переупорядочивать, игнорировать именять операции, если это нарушит program order
I Но это не значит, что всё выполняется именно так, как висходном коде
I Например: для операций над локальными переменнымиprogram order вообще не определён
20 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Программный порядок (program order)
I Отражает то, в каком порядке написан исходный кодI Компилятору запрещено переупорядочивать, игнорировать именять операции, если это нарушит program order
I Но это не значит, что всё выполняется именно так, как висходном коде
I Например: для операций над локальными переменнымиprogram order вообще не определён
21 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Частичный порядок (partial order)
I В главе 17 JLS 8 раз упоминается слово "partial order"
I Частичным порядкомhb−−→ является бинарное отношение,
которое:
I Рефлексивно: для любого элемента x выполняется xhb−−→ x
I Антисимметрично: если xhb−−→ y и y
hb−−→ x , то x и y это одно и
то же
I Транзитивно: если xhb−−→ y и y
hb−−→ z , то x
hb−−→ z
22 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Частичный порядок (partial order)
I В главе 17 JLS 8 раз упоминается слово "partial order"
I Частичным порядкомhb−−→ является бинарное отношение,
которое:
I Рефлексивно: для любого элемента x выполняется xhb−−→ x
I Антисимметрично: если xhb−−→ y и y
hb−−→ x , то x и y это одно и
то же
I Транзитивно: если xhb−−→ y и y
hb−−→ z , то x
hb−−→ z
23 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Частичный порядок (partial order)
I В главе 17 JLS 8 раз упоминается слово "partial order"
I Частичным порядкомhb−−→ является бинарное отношение,
которое:
I Рефлексивно: для любого элемента x выполняется xhb−−→ x
I Антисимметрично: если xhb−−→ y и y
hb−−→ x , то x и y это одно и
то же
I Транзитивно: если xhb−−→ y и y
hb−−→ z , то x
hb−−→ z
24 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Частичный порядок (partial order)
I В главе 17 JLS 8 раз упоминается слово "partial order"
I Частичным порядкомhb−−→ является бинарное отношение,
которое:
I Рефлексивно: для любого элемента x выполняется xhb−−→ x
I Антисимметрично: если xhb−−→ y и y
hb−−→ x , то x и y это одно и
то же
I Транзитивно: если xhb−−→ y и y
hb−−→ z , то x
hb−−→ z
25 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Частичный порядок (partial order)
I В главе 17 JLS 8 раз упоминается слово "partial order"
I Частичным порядкомhb−−→ является бинарное отношение,
которое:
I Рефлексивно: для любого элемента x выполняется xhb−−→ x
I Антисимметрично: если xhb−−→ y и y
hb−−→ x , то x и y это одно и
то же
I Транзитивно: если xhb−−→ y и y
hb−−→ z , то x
hb−−→ z
26 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I Основной принцип JMM: рассмотрим все возможныевыполнения и откинем "неправильные"
I Happens-before это частичный порядок, который долженсоблюдаться
I Запрещено видеть "будущие" записи (rhb−−→ w)
I И те, которые были перетёрлись в hb порядке:
w1hb−−→ w2
hb−−→ r
I И те, которые запрещены просто так: 17.4.8 executions andcausality requirements
27 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I Основной принцип JMM: рассмотрим все возможныевыполнения и откинем "неправильные"
I Happens-before это частичный порядок, который долженсоблюдаться
I Запрещено видеть "будущие" записи (rhb−−→ w)
I И те, которые были перетёрлись в hb порядке:
w1hb−−→ w2
hb−−→ r
I И те, которые запрещены просто так: 17.4.8 executions andcausality requirements
28 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I Основной принцип JMM: рассмотрим все возможныевыполнения и откинем "неправильные"
I Happens-before это частичный порядок, который долженсоблюдаться
I Запрещено видеть "будущие" записи (rhb−−→ w)
I И те, которые были перетёрлись в hb порядке:
w1hb−−→ w2
hb−−→ r
I И те, которые запрещены просто так: 17.4.8 executions andcausality requirements
29 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I Основной принцип JMM: рассмотрим все возможныевыполнения и откинем "неправильные"
I Happens-before это частичный порядок, который долженсоблюдаться
I Запрещено видеть "будущие" записи (rhb−−→ w)
I И те, которые были перетёрлись в hb порядке:
w1hb−−→ w2
hb−−→ r
I И те, которые запрещены просто так: 17.4.8 executions andcausality requirements
30 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I Основной принцип JMM: рассмотрим все возможныевыполнения и откинем "неправильные"
I Happens-before это частичный порядок, который долженсоблюдаться
I Запрещено видеть "будущие" записи (rhb−−→ w)
I И те, которые были перетёрлись в hb порядке:
w1hb−−→ w2
hb−−→ r
I И те, которые запрещены просто так: 17.4.8 executions andcausality requirements
31 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Семантика final полей одним слайдом
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I w и r2 – интересующие нас нас запись и чтение
I f – заморозка final поля, которое читается в r1
32 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Семантика final полей одним слайдом
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I w и r2 – интересующие нас нас запись и чтениеI f – заморозка final поля, которое читается в r1
33 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Семантика final полей одним слайдом
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I Если единственный путь от записи к чтению идёт через всеэти стрелочки, то мы не можем увидеть более ранние записи
I Если путей больше одного – как повезёт
34 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Семантика final полей одним слайдом
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I Если единственный путь от записи к чтению идёт через всеэти стрелочки, то мы не можем увидеть более ранние записи
I Если путей больше одного – как повезёт
35 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Freeze action w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Поле
Freezeслучается в конце конструктора и морозит final поля
36 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Freeze action w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Freeze action
Поле
Freezeслучается в конце конструктора и морозит final поля
37 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Freeze action w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Freeze actionПоле
Freezeслучается в конце конструктора и морозит final поля
38 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: что это? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
I r2 читает поле объекта
I Поток не создавал объектI Значит, где-то мы должны были читать адрес этого объекта
I Это называется r1dr−→ r2
39 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: что это? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
I r2 читает поле объектаI Поток не создавал объект
I Значит, где-то мы должны были читать адрес этого объекта
I Это называется r1dr−→ r2
40 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: что это? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
I r2 читает поле объектаI Поток не создавал объектI Значит, где-то мы должны были читать адрес этого объекта
I Это называется r1dr−→ r2
41 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: что это? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
dr
I r2 читает поле объектаI Поток не создавал объектI Значит, где-то мы должны были читать адрес этого объекта
I Это называется r1dr−→ r2
42 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain два потока 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
r1dr−→ r2 (читаем поле несозданного нами объекта)
43 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain два потока 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?
Есть ли adr−→ r2?
44 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain два потока 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 не возникает!
45 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: контрольный выстрелw hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; ra
local = GLOBAL; rb
int localX = local.x; r2
Есть ли здесь dr ?
46 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: контрольный выстрелw hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; ra
local = GLOBAL; rb
int localX = local.x; r2
dr?
dr?
Один из radr−→ r2 или rb
dr−→ r2 точно должен быть, но точнее
сказать невозможно47 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: что это? 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
Если чтение видит запись, то w1mc−−→ r1
48 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: что это? 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
Если пишем адрес созданного врагом объекта, то r1mc−−→ w2
49 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: что это? 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 видит w2 ⇒ w2mc−−→ r3
50 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: что это? 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
r3dr−→ r4 (читаем поле объекта)
⇒ r3mc−−→ r4
51 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: что это? 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
r3dr−→ r4 (читаем поле объекта) ⇒ r3
mc−−→ r4
52 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: что это? 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 транзитивно (т.к. частичный порядок) ⇒ w1mc−−→ r4
53 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Введение
Примеры
54 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Disclaimer
I Все примеры опасно синхронизированы (иначе зачем мысобрались?)
I Случаи чтения null не рассматриваем (даже если онивозможны)
I При составлении слайдов пострадал не один мозг
55 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Disclaimer
I Все примеры опасно синхронизированы (иначе зачем мысобрались?)
I Случаи чтения null не рассматриваем (даже если онивозможны)
I При составлении слайдов пострадал не один мозг
56 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Disclaimer
I Все примеры опасно синхронизированы (иначе зачем мысобрались?)
I Случаи чтения null не рассматриваем (даже если онивозможны)
I При составлении слайдов пострадал не один мозг
57 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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
}
Возможно ли в result получить 0?
58 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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
Действия в одном потоке образуют happens-before:
whb−−→ f , f
hb−−→ a
59 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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 видит запись a :
amc−−→ r0
60 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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
Поток 2 не создавал объект, r1 читает его поле, а r этоединственное чтение адреса объекта, поэтому dereference chain:
r0dr−→ r1
61 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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
r0dr−→ r1⇒ r0
mc−−→ r1
62 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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
amc−−→ r1 ( mc транзитивно)
63 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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
Возьмём r2 = r1, тогда r1dr−→ r2 ( dr рефлексивно)
64 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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*
Нашли всё необходимое для HB∗:
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
65 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Эталонный 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*
(whb∗
−−→ r2)⇒ result ∈ {42}
66 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив внутри final (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
}
Возможно ли в result получить 0?
67 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив внутри final (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
Действия в одном потоке образуют happens-before:
whb−−→ f , f
hb−−→ a
68 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив внутри final (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 видит запись a (т.к. простое final поле):
amc−−→ r1
69 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив внутри final (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
Поток 2 не создавал массив, r2 читает его элемент, r1 этоединственное чтение адреса массива, поэтому dereference chain:
r1dr−→ r2
70 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив внутри final (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*
Нашли всё необходимое для HB∗:
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
71 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив внутри final (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*
(whb∗
−−→ r2)⇒ result ∈ {42}
72 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив наоборот (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];
}
Возможно ли в result получить 0?
73 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив наоборот (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
}
hbhb
mc
dr
hb∗
Строим hb∗ так же как и в предыдущем случае
74 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Массив наоборот (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
}
hbhb
mc
dr
hb∗
(whb∗
−−→ r2)⇒ result ∈ {42}Результат не зависит от порядка записи final полей!
75 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Утекание this (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
}
Возможно ли в result получить 0?
76 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Утекание this (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
Действия в одном потоке образуют happens-before:
whb−−→ f , a
hb−−→ f
77 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Утекание this (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?
Но нам-то нужно fhb−−→ a!
78 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Утекание this (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?
Если ahb−−→ f и f
hb−−→ a, то a = f (антисимметричность hb )
Но публикация ссылки это никак не freeze action!
79 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Утекание this (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?
Нет hb∗ , поэтому возможны все варианты: result ∈ {0, 42}
80 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вредительское утекание this (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
}
Возможно ли в result получить 0?
81 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вредительское утекание this (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?
Действия в одном потоке образуют happens-before:
whb−−→ f , f
hb−−→ a
82 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вредительское утекание this (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
Пусть второй поток увидел GLa, тогда amc−−→ ra!
83 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вредительское утекание this (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?
Где-то должно быть dr : rbdr−→ r1 или ra
dr−→ r1
84 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вредительское утекание this (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
Если rbdr−→ r1, то мы попали, т.к. w
hb∗
−−→ r1 не строится
85 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вредительское утекание this (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
Вывод: если наш поток уже читал объект с незамороженнымиполями, то гарантий final semantics нет!
86 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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
}
Возможно ли в result получить 0?
87 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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*?
По-хорошему, нам нужно w2hb∗
−−→ r2 (иначе не запрещено видетьзапись 0 в w.x)
88 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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 не подходит для hb∗ : нет подходящего f 2hb−−→ a
89 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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 тоже не подходит для hb∗ : должно быть w2hb−−→ f 1
90 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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?
Получается, что чтению r2 не запрещено видеть 0
91 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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?
Итого: после публикации менять final поля опасноresult ∈ {0, 1, 42}
92 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Чиним 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;
}
Если публиковать ссылку после всех изменений final полей, товсё работает: result ∈ {1, 42}
93 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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
Возможно ли в result получить 0?
94 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
rb видит wb ⇒ wbmc−−→ rb
ra видит запись wa : wamc−−→ ra
95 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mc
Поток 2 пишет адрес созданного врагом объекта, поэтому
ramc−−→ wb
96 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mcdr
Поток 3 не создавал объект A, r читает его поле, а rb этоединственное чтение адреса объекта, поэтому dereference chain:
rbdr−→ r1
97 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mcdr
mc
rbdr−→ r1⇒ rb
mc−−→ r1
98 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mc
mc
mc
mc транзитивно (т.к. частичный порядок) ⇒ wamc−−→ r1
99 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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
Возьмём r2 = r1, тогда r1dr−→ r2 ( dr рефлексивно)
100 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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*
Нашли всё необходимое для HB∗:
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2101 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
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*
(whb∗
−−→ r2)⇒ result ∈ {42}
102 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Вопросы?
103 / 103 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved