Java Memory Model
З АЧ Е М Н У Ж Н А J M M ?
Оригинальная Java memory model была разработана в 1995 году.
x = y = 0
x = y = 0
x = y = 0
x = y = 0
x = y = 0
1. Компилятор может в качестве оптимизации свободно переупорядочивать определенные инструкции, если это не меняет семантику
JMM оперирует терминами actions (read, write, lock, unlock,…)
…. synchronized(this) { ……
ГА РА Н Т И И V O L AT I L E
volatile int x = 0;
boolean keepRunning = true;
Point p = new Point(1, 1);
Point p = new Point(1, 1);
Point p = new Point(1, 1);
Point p = new Point(1, 1);
Point p = new Point(1, 1);
public class HelloPrinter { private boolean sayHello;
public class HelloPrinterFactory { private HelloPrinter instance;
public class HelloPrinterFactory { private HelloPrinter instance;
Ссылка и состояние объекта должны быть видимы потоку.
public class HelloPrinterFactory { private volatile HelloPrinter instance;
public class HelloPrinterFactory { private int value; // для 32 битных примитивов (не для double и long)
public class HelloPrinterFactory { private static final HelloPrinter instance = new HelloPrinter();
public class HelloPrinterFactory { private static class Holder { private static final HelloPrinter instance = new
Ни Java Memory Model, ни Java language specification не дают определения immutable.
public final class Person { private final int age; private final String name;
public final class Person { private final int age; private final String name;
public final class Corporation { private final Set<String> employees= new HashSet<String>();
public final class Corporation { private final Set<String> employees= new HashSet<String>();
public final class Person { private int age; private String name;
Одновременно final volatile - некорректная комбинация модификаторов
216.44K
Category: programmingprogramming

JMM (1)

1. Java Memory Model

2.

УЗНАЕМ
Что такое JMM
Reordering
Happens-before relationship
Гарантии volatile
Double-check locking
Singleton pattern и JMM
Safe publication idioms
Immutable и effectively immutable objects
Гарантии final

3.

М О Ж Н О Л И В Ы З В АТ Ь G R E E T ( ) И Н Е У В И Д Е Т Ь “ H E L L O ” ?
public class HelloPrinter {
private boolean sayHello = true;
public synchronized void greet() {
if (sayHello) {
System.out.println("hello");
}
sayHello = false;
}
}

4. З АЧ Е М Н У Ж Н А J M M ?

variable = 3;
Отвечает на вопрос: ”При каких условиях поток, который прочитал
эту переменную, увидит значение 3?”

5.

З АЧ Е М Н У Ж Н А J M M ?
• Описывает как потоки взаимодействуют через память. Когда
изменения, сделанные одним потоком, будут видны другому
• Описывает корректное поведение программы в многопоточной
среде на различных архитектурах с различными hardware memory
model
• Описывает работу с shared variables

6. Оригинальная Java memory model была разработана в 1995 году.

J MM
Оригинальная Java memory model была разработана в 1995 году.
Была обновлена через Java Community Process (JSR-133) в 2004г.
Изменения появились в Java 5.0.
Описывается в 17 главе JLS:
http://java.sun.com/docs/books/jls/third_edition/html/memory.html

7. x = y = 0

КАКИЕ ВОЗМОЖНЫ ВАРИАНТЫ ?
x=y=0
Thread 1
Thread 2
a = x;
y = 1;
b = y;
x = 1;
a=?b=?

8. x = y = 0

КАКИЕ ВОЗМОЖНЫ ВАРИАНТЫ ?
x=y=0
Thread 1
Thread 2
a = x;
y = 1;
b = y;
x = 1;
1.
2.
3.
a = 0; b = 0;
a = 1; b = 0;
a = 0; b = 1;

9. x = y = 0

КАКИЕ ВОЗМОЖНЫ ВАРИАНТЫ ?
x=y=0
Thread 1
Thread 2
a = x;
y = 1;
b = y;
x = 1;
1.
2.
3.
4.
a = 0; b = 0;
a = 1; b = 0;
a = 0; b = 1;
a = 1; b = 1; oO ?

10. x = y = 0

В О З М О Ж Е Н Р Е О РД Е Р И Н Г
x=y=0
Thread 1
Thread 2
a = x;
y = 1;
b = y;
x = 1;
1.
2.
3.
4.
a = 0; b = 0;
a = 1; b = 0;
a = 0; b = 1;
a = 1; b = 1; oO ?

11. x = y = 0

Р Е О РД Е Р И Н Г
x=y=0
Thread 1
Thread 2
y = 1;
a = x;
x = 1;
b = y;
1.
2.
3.
4.
a = 0; b = 0;
a = 1; b = 0;
a = 0; b = 1;
a = 1; b = 1;

12. 1. Компилятор может в качестве оптимизации свободно переупорядочивать определенные инструкции, если это не меняет семантику

ИЗ - З А Ч Е Г О П Р О И С Х О Д И Т R E O R D E R I N G ?
1. Компилятор может в качестве оптимизации свободно
переупорядочивать определенные инструкции, если это не
меняет семантику программы.
2. Процессору позволяется исполнять операции не по порядку в
некоторых обстоятельствах.
3. Кэшу, как правило, позволяется выполнять обратную запись
переменных в основную память не в том порядке, в котором они
были записаны программой.

13.

H A P P E N S - B E F O R E R E L AT I O N S H I P
JMM оперирует терминами actions (read, write, lock, unlock,…)
JMM гарантирует что поток, выполнивший action B увидит результат
действия A, только если A и В состоят в отношении happens-before. (A
happens-before B)

14. JMM оперирует терминами actions (read, write, lock, unlock,…)

H A P P E N S - B E F O R E Т РА Н З И Т И В Е Н
JMM оперирует терминами actions (read, write, lock, unlock,…)
JMM гарантирует что поток, выполнивший action B увидит результат
действия A, только если A и В состоят в отношении happens-before. (A
happens-before B)
hb(x, y) и hb(y, z), то hb(x, z)

15.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
lock M1
Thread 2
lock M2
x=1
temp = x
unlock M1
unlock M2
y=2
temp2 = y

16.

Н Е К О Т О Р Ы Е HB
• Действия в потоке happens-before последующего действия в этом же потоке,
которое идет позже в программном порядке
• Разблокировка монитора happens-before каждой последующей блокировки
того же монитора
• Запись в поле volatile happens-before каждого последующего считывания того
же самого volatile
• Вызов Thread::start() у потока happens-before первого действия в этом потоке
• Завершение потока T1 happens-before момента, когда поток T2 определил, что
T1 завершился, вызвав T1.join() или T1.isAlive() (и получив false)
• Завершение конструктора объекта happens-before запуска финализации для
него
• Еще несколько пунктов …

17.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
lock M1
Thread 2
lock M2
x=1
temp = x
unlock M1
unlock M2
y=2
temp2 = y

18.

T 2 Н Е О Б Я З А Н У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T1
Thread 1
lock M1
Thread 2
lock M2
x=1
temp = x
unlock M1
unlock M2
y=2
temp2 = y

19.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
lock M1
Thread 2
lock M1
x=1
temp = x
unlock M1
unlock M1
y=2
temp2 = y

20.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
lock M1
Thread 2
lock M1
x=1
temp = x
unlock M1
unlock M1
y=2
temp2 = y
да

21.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
lock M1
Thread 2
lock M1
x=1
temp = x
да
unlock M1
unlock M1
y=2
temp2 = y
нет

22.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
y=2
Thread 2
lock M1
lock M1
temp = x
x=1
unlock M1
unlock M1
temp2 = y

23.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
y=2
Thread 2
lock M1
lock M1
temp = x
да
x=1
unlock M1
unlock M1
temp2 = y
да

24.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
x=1
y – volatile переменная
Thread 2
temp = y
y=2
temp2 = x

25.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
x=1
y – volatile переменная
Thread 2
temp = y
y=2
temp2 = x
да

26.

О Б Я З А Н Л И T 2 У В И Д Е Т Ь И З М Е Н Е Н И Я С Д Е Л А Н Н Ы Е T 1?
Thread 1
x=1
y – volatile переменная
Thread 2
temp = y
да
temp2 = x
да
y=2

27. …. synchronized(this) { ……

SYNCHRONIZED И REORDERING
….
synchronized(this) {
……
……
}
….

28.

V O L AT I L E И R E O R D E R I N G
……
volatile store
……

29.

V O L AT I L E И R E O R D E R I N G
……
volatile read
……

30. ГА РА Н Т И И V O L AT I L E

• Гарантии happens-before
• Гарантии с reordering
• Атомарные запись и чтение актуальных значений (даже для
Long и Double на 32x разрядных архитектурах)

31. volatile int x = 0;

+ + X Э Т О 3 О П Е РА Ц И И , А Н Е О Д Н А
volatile int x = 0;
public void increment() {
++x; //todo не делать так
}

32. boolean keepRunning = true;

БЕСКОНЕЧНЫЙ ЦИКЛ
boolean keepRunning = true;
public void run() {
while(keepRunning) {

}
}
public void setKeepRunning(boolean v){…}

33. Point p = new Point(1, 1);

БЕЗОПАСНАЯ ИНИЦИАЛИЗАЦИЯ
Point p = new Point(1, 1);
Thread 1 Thread 2
p = new Point(2, 2);
class Point {
int x,y;
}
a = p.getX();
a=?

34. Point p = new Point(1, 1);

БЕЗОПАСНАЯ ИНИЦИАЛИЗАЦИЯ
Point p = new Point(1, 1);
Thread 1 Thread 2
p = new Point(2, 2);
a = p.getX();
1. a = 1;
2. a = 2;

35. Point p = new Point(1, 1);

БЕЗОПАСНАЯ ИНИЦИАЛИЗАЦИЯ
Point p = new Point(1, 1);
Thread 1 Thread 2
p = new Point(2, 2);
a = p.getX();
1. a = 1;
2. a = 2;
3. a = 0; oO ??

36.

ССЫЛКА НА ОБЪЕКТ МОЖЕТ ВЕРНУТЬСЯ БЫСТРЕЕ
З А В Е Р Ш Е Н И Я К О Н С Т Р У К Т О РА
Point p = new Point(1, 1);
Thread 1 Thread 2
p = new Point(2, 2);
a = p.getX();
1. a = 1;
2. a = 2;
3. a = 0; oO ??

37. Point p = new Point(1, 1);

Э Т О НЕ ПОМОЖЕТ
Point p = new Point(1, 1);
Thread 1 Thread 2
synchronized(this) {
a = p.getX();
p = new Point(2, 2);
}
1. a = 1;
2. a = 2;
3. a = 0; oO ??

38. Point p = new Point(1, 1);

Э Т О Т О ЖЕ НЕ ПОМОЖЕТ
Point p = new Point(1, 1);
Thread 1 Thread 2
Point temp = new Point(2, 2);
p = temp;
a = p.getX();
1. a = 1;
2. a = 2;
3. a = 0; oO ??

39. public class HelloPrinter { private boolean sayHello;

THREAD -SAFE ЛИ ДАННЫЙ КОД ?
public class HelloPrinter {
private boolean sayHello;
HelloPrinter() {
sayHello = true;
}
Конструктор объекта и его синхронизованные методы
не находятся в отношении happens-before
public synchronized void greet() {
if (sayHello) {
System.out.println("hello");
}
sayHello = false;
}
}

40. public class HelloPrinterFactory { private HelloPrinter instance;

DOUBLE-CHECK LOCKING @NOTTHREADSAFE
public class HelloPrinterFactory {
private HelloPrinter instance;
public HelloPrinter getPrinter() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = new HelloPrinter();
}
}
}
return instance;
}
}

41. public class HelloPrinterFactory { private HelloPrinter instance;

@NOTTHREADSAFE НЕ ПОМОЖЕТ
public class HelloPrinterFactory {
private HelloPrinter instance;
public HelloPrinter getPrinter() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
HelloPrinter temp = new HelloPrinter();
instance = temp;
}
}
}
return instance;
}

42. Ссылка и состояние объекта должны быть видимы потоку.

S AF E P U B L I C AT I O N I D I O M S
Ссылка и состояние объекта должны быть видимы потоку.
Инициализация в static инициализаторе
Сохранять ссылку на объект в volatile
Сохранять ссылку в final (this не убегает из конструктора)
Сохранять ссылку в поле, корректно используя синхронизацию

43. public class HelloPrinterFactory { private volatile HelloPrinter instance;

DOUBLE-CHECK LOCKING @THREADSAFE
public class HelloPrinterFactory {
private volatile HelloPrinter instance;
public HelloPrinter getPrinter() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = new HelloPrinter();
}
}
}
return instance;
}
}

44.

DOUBLE-CHECK LOCKING @THREADSAFE
public class HelloPrinterFactory {
private HelloPrinter instance; //если все поля объекта final
public HelloPrinter getPrinter() {
HelloPrinter temp = this.instance;
if (temp == null) {
synchronized (this) {
if (this.instance == null) {
this.instance = temp = new HelloPrinter();
}
}
}
return temp;
}
}

45. public class HelloPrinterFactory { private int value; // для 32 битных примитивов (не для double и long)

DOUBLE-CHECK LOCKING @THREADSAFE
public class HelloPrinterFactory {
private int value; // для 32 битных примитивов (не для double и long)
public int getValue() {
int value = this.value;
if (value == null) {
synchronized (this) {
if (this.value == 0) {
value = this.value = compute();
}
}
}
return value;
}

46. public class HelloPrinterFactory { private static final HelloPrinter instance = new HelloPrinter();

С ТАТ И Ч Е С К А Я И Н И Ц И А Л И З А Ц И Я @ T H R E A D S A F E
public class HelloPrinterFactory {
private static final HelloPrinter instance = new HelloPrinter();
public HelloPrinter getInstance() {
return instance;
}
}

47. public class HelloPrinterFactory { private static class Holder { private static final HelloPrinter instance = new

ЛУЧШИЙ СПОСОБ ЛЕНИВОЙ ИНИЦИАЛИЗАЦИИ @THREADSAFE
public class HelloPrinterFactory {
private static class Holder {
private static final HelloPrinter instance = new HelloPrinter();
}
public HelloPrinter getInstance() {
return Holder.instance;
}
}

48. Ни Java Memory Model, ни Java language specification не дают определения immutable.

I M M U TA B L E О Б Ъ Е К Т Ы
Ни Java Memory Model, ни Java language specification не дают
определения immutable.

49. public final class Person { private final int age; private final String name;

I M M U TA B L E ЛИ О Б Ъ Е К Т Ы Д А Н Н О Г О К Л А С С А ?
public final class Person {
private final int age;
private final String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() { return age; }
public String getName() { return name;}
}

50. public final class Person { private final int age; private final String name;

I M M U TA B L E ЛИ О Б Ъ Е К Т Ы Д А Н Н О Г О К Л А С С А ?
public final class Person {
private final int age;
private final String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
final поля объекта будут корректно инициализированы до
возвращения ссылки на конструируемый объект и видны всем
потокам.

51. public final class Corporation { private final Set<String> employees= new HashSet<String>();

А Ч Т О Е С Л И П ОЛ Е F I N A L , Н О Е Г О С О С Т О Я Н И Е Н Е F I N A L ?
public final class Corporation {
private final Set<String> employees= new HashSet<String>();
public Corporation () {
employees.add(“Alex");
employees.add(“Ben");
}
public boolean isEmployee(String name) {
return employees.contains(name);
}
}

52. public final class Corporation { private final Set<String> employees= new HashSet<String>();

@THREADSAFE
public final class Corporation {
private final Set<String> employees= new HashSet<String>();
public Corporation () {
employees.add(“Alex");
employees.add(“Ben");
}
}
final гарантирует, что ссылка на объект вернется после
завершения конструктора, так что и тут все ок

53. public final class Person { private int age; private String name;

E F F E C T I V E LY I M M U TA B L E
public final class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() { return age; }
public String getName() { return name;}
}

54. Одновременно final volatile - некорректная комбинация модификаторов

F I N A L V O L AT I L E
Одновременно final volatile - некорректная комбинация
модификаторов

55.

О Б С УД И Л И
Что такое JMM
Reordering
Happens-before relationship
Гарантии volatile
Safe publication idioms
Гарантии final
English     Русский Rules