Максим расскажет, что такое Java Memory Model, какие нюансы ожидают разработчика при написании мультипоточного кода, и как это учитывать в Android-приложениях.
4. 3
Reordering
int a, b;
void foo() {
int l1 = a;
int l3 = b;
int l2 = l1 + 10;
int l4 = l2 % 3;
}
int a, b;
void foo() {
int l1 = a;
int l2 = l1 + 10;
int l3 = b;
int l4 = l2 % 3;
}
5. 4
Reordering – ограничения
int a, b;
void foo() {
int l2 = l1 + 10;
int l1 = a;
int l3 = b;
int l4 = l2 % 3;
}
int a, b;
void foo() {
int l1 = a;
int l2 = l1 + 10;
int l3 = b;
int l4 = l2 % 3;
}
Reordering не меняет семантику кода в
одном потоке
10. Data race
9
• Один поток читает данные
• Второй поток пишет данные
• Эти два действия не синхронизированы
11. Итоги & QA - I
10
• Reordering оптимизирует код в одном потоке
• Reordering ломает семантику многопоточного кода
• Нужен порядок между действиями в разных потоках
• Без синхронизации ломается семантика
Вопросы?
Базовые принципы
12. Java memory model
11
«A memory model describes, given a program and an
execution trace of that program, whether the execution
trace is a legal execution of the program.»
JSR 133
22. Causality
21
• Все действия группируются на коммиты
• Коммиты выстраиваются в строгий порядок
• Действие не может попасть в коммит, если это станет
причиной состояния гонки
26. JVM vs DVM
25
Stack Register
Картинки из статьи https://markfaction.wordpress.com/2012/07/15/stack-based-vs-register-based-virtual-machine-architecture-and-the-dalvik-vm/
39. Bytecode
38
public foo(I)I
L0
LINENUMBER 34 L0
ILOAD 1
BIPUSH 10
IADD
ISTORE 2
L1
LINENUMBER 35 L1
ILOAD 2
IRETURN
L2
LOCALVARIABLE this
Lgenerator/android/TestJava;
L0 L2 0
LOCALVARIABLE a I L0 L2 1
LOCALVARIABLE b I L1 L2 2
MAXSTACK = 2
MAXLOCALS = 3
.method public foo(I)I
.registers 3
.param p1, "a" # I
.prologue
.line 27
add-int/lit8 v0, p1, 0xa
.line 29
.local v0, "b":I
return v0
.end method
JVM DVM
int a
int b
return b
b = a + 10
int a
int b
return b
b = a + 10
40. Synchronized
39
public synchronized int foo(int a) {
int b;
b = a + 10;
return b;
}
public int foo(int a) {
synchronized (this) {
int b;
b = a + 10;
return b;
}
}
41. Bytecode synchronized method
40
public synchronized foo(I)I
L0
LINENUMBER 34 L0
ILOAD 1
BIPUSH 10
IADD
ISTORE 2
L1
LINENUMBER 35 L1
ILOAD 2
IRETURN
L2
LOCALVARIABLE this Lgenerator/
android/TestJava; L0 L2 0
LOCALVARIABLE a I L0 L2 1
LOCALVARIABLE b I L1 L2 2
MAXSTACK = 2
MAXLOCALS = 3
.method public declared-synchronized
foo(I)I
.registers 3
.param p1, "a" # I
.prologue
.line 21
monitor-enter p0
add-int/lit8 v0, p1, 0xa
.line 22
.local v0, "b":I
monitor-exit p0
return v0
.end method
JVM DVM
b = a + 10
44. DVM synchronized method div
43
.method public final declared-synchronized fooDangerous(I)I
.registers 4
.param p1, "a" # I
.prologue
.line 27
monitor-enter p0
:try_start_1
div-int/lit8 v0, p1, 0xa
:try_end_3
.catchall {:try_start_1 .. :try_end_3} :catchall_5
.line 28
.local v0, "b":I
monitor-exit p0
return v0
.line 27
.end local v0 # "b":I
:catchall_5
move-exception v1
monitor-exit p0
throw v1
.end method
.method public declared-synchronized
foo(I)I
.registers 3
.param p1, "a" # I
.prologue
.line 21
monitor-enter p0
add-int/lit8 v0, p1, 0xa
.line 22
.local v0, "b":I
monitor-exit p0
return v0
.end method
b = a / 10b = a + 10
45. DMV synchronized method try-catch
44
• Вызов метода
• Создание объекта
• Деление целых чисел
• Бросок исключения
• Каст
• Изменение поля класса
• Загрузка класса
46. Итоги & QA - IV
45
• Байткод dalvik отличается от JVM
• Не все флаги методов работают так же
• Есть оптимизация в зависимости от опкодов
DVM bytecode
47. Links
46
• https://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf
JSR 133
• http://shipilev.net/blog/2014/jmm-pragmatics/
Очень крутое объяснение JMM
• http://developer.android.com/intl/ru/training/articles/smp.html
Гайд по MM в Android
• http://gee.cs.oswego.edu/dl/jmm/cookbook.html
JMM для авторов компиляторов
• http://jcip.net/
Отличная книга про JMM