Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Java 並行処理の基礎update1

2,020 views

Published on

Published in: Education
  • Be the first to comment

Java 並行処理の基礎update1

  1. 1. Java 並行処理の基礎 update 1@hakurai2021/08/28
  2. 2. Java 並行処理入門 update 1@hakurai2021/08/28
  3. 3. 自己紹介✤ twitter: hakurai✤ Javaとか✤ JavaFX!JavaFX!
  4. 4. Java言語仕様 イントロダクションより✤ プログラミング言語Javaは、並行処理の可能なクラスに基づく汎用目 的のオブジェクト指向言語です。
  5. 5. Java言語仕様 イントロダクションより✤ プログラミング言語Javaは、並行処理の可能なクラスに基づく汎用目 的のオブジェクト指向言語です。
  6. 6. 言語仕様レベルで並行処理をサポート✤ synchronized✤ volatile✤ final
  7. 7. Java仮想マシンで何が行われるかという基礎的なおはなし
  8. 8. まずは変数とメモリについて
  9. 9. 変数について✤ 変数とは記憶領域のこと 変数1 変数2✤ Javaの変数は型を持つ 変数3✤ プリミティブ型✤ 参照型 ✤ クラス型 ✤ インターフェイス型 ✤ 配列型✤ null型
  10. 10. メイン・メモリと作業メモリ✤ 変数は、すべてのスレッドから共有されるメイン・メモリ中に保持さ れる。✤ すべてのスレッドには作業メモリという、スレッドによって使用や代 入が行われる変数の作業コピーを保持する領域が用意される。 Java仮想マシン仕様 第2版 359Pより
  11. 11. スレッドは作業メモリを利用するスレッド1 スレッド2実行エンジン 実行エンジン 変数A 変数A 変数B 作業メモリ変数A 変数B メイン・メモリ変数C 変数D
  12. 12. 変数は作業メモリに転送されるスレッド1 スレッド2 ✤ メイン・メモリから変数が作業メモリ実行エンジン 実行エンジン に転送される 変数A 100 変数B変数A 変数B 100変数C 変数D
  13. 13. スレッド1上で変数Aに値を代入するとスレッド1 スレッド2 ✤ スレッド1の作業エンジンが変数Aに実行エンジン 実行エンジン 200を代入する 変数A 200 変数B ✤ Java仮想マシンの仕様上メイン・メモ リに書き込むタイミングは自由変数A 変数B 100変数C 変数D
  14. 14. この状態でスレッド2が変数Aを読み込むとスレッド1 スレッド2 ✤ スレッド2の作業メモリ上の変数Aは古実行エンジン 実行エンジン いまま 変数A 変数A 200 100 変数B ✤ スレッド2からは変数Aの値が100に見 える変数A 変数B 100変数C 変数D
  15. 15. 変数の一貫性を保つ必要がある 変数A 変数A 200 200 変数B
  16. 16. synchronized & volatile
  17. 17. synchronizedの役割(相互排除)✤ すべてのオブジェクトにはモニタが存在する✤ モニタを取得してオブジェクトをロックするのがsynchronized✤ 同時にモニタを取得できるのは一つのスレッドだけ✤ オブジェクトのロックを取得できたスレッドのみ処理を実行させる✤ synchronized文を抜けるとロックは自動的に解放される
  18. 18. メモリの可視性に関する規則
  19. 19. ロックと変数(メモリの可視性)✤ スレッドが任意のロックに対してアンロックを実行する場合、最初に その作業メモリ中のすべての代入値をメイン・メモリにコピーしてお かなければならない✤ ロックは、スレッドの作業メモリからすべての変数をフラッシュする かのように振る舞う Java仮想マシン仕様 第2版 364Pより
  20. 20. ロックと変数に関する規則1✤ 変数のスレッドに対する代入と、それに続くアンロックの間には、必 ずストアが介在し、更にそのストアに対応する書き込みは、必ずアン ロックに先立って行わなければならない✤ つまり、作業メモリ内で変更された変数はアンロック前にメイン・メ モリへのコピーが完了していなければならない
  21. 21. ロックと変数に関する規則2✤ 任意のロックLに対するスレッドTによるロックLと、それに続く変数Vに対するスレッ ドTによる使用やストアの間には、必ず変数Vに対する代入やロードが介在する✤ さらにロード時には、メイン・メモリからみた場合、そのロードに対する読み込み は、必ずロックの後に行わなければならない。✤ つまり、ロック後に使用する変数は、使用する前にメイン・メモリからロードされな ければならない✤ もしくは、代入によって変数を上書きする
  22. 22. ロックで変数の一貫性を保つことができる
  23. 23. ロックの例✤ モニタの解放後に他のスレッドから最新の値が見えることを保証する private final Object lock = new Object(); private List<String> list; private String get(int index){ synchronized (lock){ return list.get(index); } }
  24. 24. ダメな例 private final Object lock = new Object(); private List<String> list; public void add(String text){ synchronized (lock){ list.add(text); } } public String get(int index){ return list.get(index); }
  25. 25. ダメな例 private final Object lock = new Object(); private List<String> list; public void add(String text){ synchronized (lock){ list.add(text); } } public String get(int index){ return list.get(index); } 陳腐化したデータ
  26. 26. ダメな例 private final Object lock = new Object(); private List<String> list; public void add(String text){ synchronized (lock){ 最新の状態のlistが見えることを保証していない list.add(text); ・予期しない値が返される } ・IllegalArgumentException } public String get(int index){ return list.get(index); } 陳腐化したデータ
  27. 27. アンロックが実行されるとスレッド1 スレッド2 ✤ メイン・メモリの変数Aの値は200に更実行エンジン 実行エンジン 新される 変数A 変数A 200 100 変数B変数A 変数B 200変数C 変数D
  28. 28. ロックが実行されるとスレッド1 スレッド2 ✤ スレッド2の作業メモリの変数Aの値は実行エンジン 実行エンジン 200に更新される 変数A 変数A 200 200 変数B変数A 変数B 200変数C 変数D
  29. 29. 変数の一貫性の保たれるコードpublic class Test { private int a; public synchronized int getA() { return a; } public synchronized void setA(int a) { this.a = a; }}
  30. 30. volatileの役割✤ フィールドをvolatileとして宣言することによって、Javaのメモリ・モ デルはすべてのスレッドから見てその変数の値の整合性が保たれるこ とを保証する Java言語仕様 第3版 177Pより
  31. 31. volatile変数に対する規則✤ 変数がvolatileとして宣言されている場合、各スレッドの動作に次の 制約が追加される✤ 変数Vに対するスレッドTによる使用は、変数Vに対するスレッドTに よる以前の動作がロードである場合にのみ許される✤ 変数Vに対するスレッドTによるロードは、変数Vに対するスレッドT による次の動作が使用である場合にのみ許される Java仮想マシン仕様 第2版 364Pより
  32. 32. つまりvolatile変数は使用される前にメイン・メモリから最新の値がコピーされる
  33. 33. volatile変数の使用スレッド1 スレッド2 ✤ 使用される前にメイン・メモリから最実行エンジン 実行エンジン 新の値がコピーされる 変数A 変数A 200 200 変数B 変数A 変数B 200 変数C 変数D
  34. 34. volatile変数の代入スレッド1 スレッド2 ✤ 代入された直後に最新の値がメイン・実行エンジン 実行エンジン メモリにコピーされる 変数A 変数A 200 100 変数B 変数A 変数B 200 変数C 変数D
  35. 35. すべてのスレッドから変数の最新の値を見ることができる
  36. 36. リオーダーの禁止✤ 非volatile変数の読み書きとの順序替え(reordering)の禁止 private int num = 0; private volatile boolean initialized; public void run(){ num = 100; initialized = true; }
  37. 37. finalフィールド✤ finalフィールドによって、プログラマは同期化を用いることなく、ス レッド・セーフな不変オブジェクトを実装できるようになる✤ 生成中のオブジェクトへの参照は、該当オブジェクトのコンストラク タが完了する前に他のスレッドから観測される場所に書き込んではい けない Java言語仕様 第3版 500Pより
  38. 38. 不変クラスの例 public final class Test { private String text; private List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { return text; } public List<Integer> getIntegerList() { return new ArrayList<>(integerList); } }
  39. 39. 不変クラスの例?? public final class Test { private String text; private List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { return text; } public List<Integer> getIntegerList() { return new ArrayList<>(integerList); } }
  40. 40. 不変クラスの(ダメな)例 public final class Test { private String text; private List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { return text; } public List<Integer> getIntegerList() { return new ArrayList<>(integerList); } }
  41. 41. 不変クラスの作成ガイドライン✤ すべてのフィールドがfinalである✤ クラスがfinalとして宣言されている✤ 作成時にthis 参照がコンストラクター外部に渡されない✤ 配列、コレクションなどの可変オブジェクトや、Date などの可変クラスへの参照を含 むフィールドが以下の条件を満たす✤ privateである✤ 返されないか、呼び出し側に公開されない✤ 参照の対象となるオブジェクトへの唯一の参照である✤ 参照するオブジェクトの状態を、そのオブジェクトが作成された後で変更しない Javaの理論と実践: 可変性か、不変性か? http://www.ibm.com/developerworks/jp/java/library/j-jtp02183/index.html
  42. 42. 不変クラスの(ダメな)例 public final class Test { private String text; private List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { return text; } public List<Integer> getIntegerList() { return new ArrayList<>(integerList); } }
  43. 43. 不変クラスの(ダメな)例 public final class Test { private String text; private List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { nullの可能性がある return text; } public List<Integer> getIntegerList() { return new ArrayList<>(integerList); } }
  44. 44. 不変クラスの(ダメな)例 public final class Test { private String text; private List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { nullの可能性がある return text; } public List<Integer> getIntegerList() { 例外が発生する可能性 return new ArrayList<>(integerList); } がある }
  45. 45. 不変クラスの(正しい)例 public final class Test { private final String text; private final List<Integer> integerList; public Test(String text, List<Integer> integerList) { this.text = text; this.integerList = new ArrayList<>(integerList); } public String getText() { return text; } public List<Integer> getIntegerList() { return new ArrayList<>(integerList); } }
  46. 46. 並行処理難しい!

×