Семантика final полей в java

Post on 21-May-2015

191 views 1 download

Tags:

description

Слово final многогранно и многокрасочно. Ни для кого не секрет, что оно может запрещать наследование классов и запрещать изменение значений полей. Более узкому кругу лиц знакомо, что final обладает особыми свойствами при работе нескольких потоков. К сожалению, в сети много мифов о том какие свойства даёт final, и нет внятного толкования почему и как оно работает. Даже на докладах про java memory model final’ы упоминают лишь вскользь. Что же делать? Совсем не использовать final’ы? Это явно не выбор человека, который любит докапываться до истины! В данном докладе мы расставим все точки в слове final, рассмотрим на конкретных примерах как работает раздел 17.5 спецификации языка Java "Final Field Semantics", а также то, какие бывают типичные ошибки в трактовке спецификации.

transcript

Семантика final полей в java

Владимир Ситников, Валентин Коваленкоsitnikov@netcracker.com, @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