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 Concurrency, A(nother) Peek Under the Hood [Java Day Tokyo 2016 3-C]

42 views

Published on

去年のJJUGナイトセミナー JVM特集で実施した「HotSpot のロック: A Peek Under the Hood」の続きのセッションです。

java.util.concurrentやJava Memory Modelの実装について、いくつかご紹介します。これらで不可欠な技術がJVMとクラス・ライブラリでどのように提供されているかを簡単に説明します。たとえば、volatileキーワードの利用時に、JITコンパイルによって生成されるコードはどのように変わるかを分析します。

Published in: Software
  • Be the first to comment

  • Be the first to like this

Java Concurrency, A(nother) Peek Under the Hood [Java Day Tokyo 2016 3-C]

  1. 1. Java Concurrency, A(nother) Peek Under the Hood David Buck 日本オラクル JavaDay Tokyo 2016
  2. 2. 自己紹介 バック デイビッド • Java SE サステイニング エンジニアリング • JVM のバグを直す人 • OpenJDK 8 Updates Project Maintainer • 趣味:プログラミング
  3. 3. 予定 • はじめに • 背景 – 余談その1:特殊相対性理論 • 歴史 • 実装 – 余談その2:HSDIS • 将来 • まとめ
  4. 4. はじめに
  5. 5. 動機 「私が並行処理のコードを書かないのに。。。」
  6. 6. Web サーバ picture: Coolcaesar at the English language Wikipedia [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0/)]
  7. 7. GUI
  8. 8. ライブラリ picture: David Vignoni / ICON KING (http://icon-king.com) [LGPL (http://www.gnu.org/licenses/lgpl.html) or LGPL (http://www.gnu.org/licenses/lgpl.html)]
  9. 9. バッチ処理 picture: US Social Security Administration (http://www.ssa.gov/history/acalcs.html) [Public domain]
  10. 10. 「私が並行処理のコードを書かないのに。。。」
  11. 11. 「私が並行処理のコードを書かないのに。。。」
  12. 12. 競合状態 picture: Sakurambo at English Wikipedia [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0/)]
  13. 13. ハイゼンバグ Bug Heisenberg Heisenbug picture: Bundesarchiv, Bild 183-R57262 / Unknown / CC-BY-SA 3.0 [CC BY-SA 3.0 de (http://creativecommons.org/licenses/by-sa/3.0/de/deed.en)]
  14. 14. 観察者効果 picture: Christian Schirm (Own work) [CC0]
  15. 15. ハイゼンバグを防ぐために • Java Memory Model • synchronized キーワード • java.util.concurrent
  16. 16. ハイゼンバグを防ぐために • Java Memory Model • synchronized キーワード • java.util.concurrent • XXX をやっちゃ駄目! • YYY をしなっきゃ!
  17. 17. a² + b² == c²
  18. 18. picture: WTF Public License, Version 2
  19. 19. 背景
  20. 20. メモリモデル
  21. 21. メモリモデル 定義その1 書き込まれた値が正しく読み込まれる条件を 明確にする仕様
  22. 22. void hogeMethod1() { int localA = 42; assert localA == 42; }
  23. 23. static int staticA; void hogeMethod2() { staticA = 42; assert staticA == 42; }
  24. 24. int data = 0; boolean ready = false; void hoge3() { while (!ready) {}; assert data == 42; } void hoge4() { data = 42; ready = true; }
  25. 25. 犯人その1
  26. 26. 犯人その2
  27. 27. メモリオーダリング void hoge5() { a = 1; b = 2; c = 3; d = 4; e = 5; a = a + 1; }
  28. 28. メモリオーダリング void hoge5() { a = 1; b = 2; c = 3; d = 4; e = 5; a = a + 1; } void hoge5() { a = 2; b = 2; c = 3; d = 4; e = 5; }
  29. 29. メモリオーダリング void hoge5() { a = 1; b = 2; c = 3; d = 4; e = 5; a = a + 1; } void hoge5() { b = 2; c = 3; d = 4; e = 5; a = 2; }
  30. 30. 原則 シングルスレッドコードの振る舞いが 変わらない
  31. 31. アウト・オブ・オーダー実行 picture: Amit6, original version (File:Superscalarpipeline.png) by User:Poil (Own work) [CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)]
  32. 32. CPUの相違 Type Alpha ARMv7 PA- RISC POWER SPARC RMO SPARC PSO SPARC TSO x86 x86 oostore AMD64 IA-64 zSeries load- load Y Y Y Y Y Y Y load- store Y Y Y Y Y Y Y store- store Y Y Y Y Y Y Y Y store- load Y Y Y Y Y Y Y Y Y Y Y Y Atomic (loads) Y Y Y Y Y Atomic (stores) Y Y Y Y Y Y Depend ent loads Y instruct ion cache Y Y Y Y Y Y Y Y Y Y chart source: https://en.wikipedia.org/wiki/Memory_ordering
  33. 33. CPU次第 緩い 厳しい Alpha X86
  34. 34. メモリバリア int data = 0; boolean ready = false; void hoge3() { while (!ready) {}; assert data == 42; } void hoge4() { data = 42; ready = true; }
  35. 35. メモリバリア int data = 0; boolean ready = false; void hoge3() { while (!ready) {}; assert data == 42; } void hoge4() { data = 42; ready = true; }
  36. 36. メモリバリア int data = 0; boolean ready = false; void hoge3() { while (!ready) {}; assert data == 42; } void hoge4() { data = 42; ready = true; }
  37. 37. メモリバリアの種類 • store-store • store-load • load-store • load-load
  38. 38. コンパイラのバリア • GCC – __asm__ __volatile__("":::"memory"); • VC++ – _ReadBarrier – _WriteBarrier – _ReadWriteBarrier
  39. 39. 余談その1:特殊相対性理論 picture: Sakurambo (Own work) [Public domain]
  40. 40. 余談その1:特殊相対性理論 A B C
  41. 41. 余談その1:特殊相対性理論 A B C A, B, C
  42. 42. 余談その1:特殊相対性理論 A B C A, B, C C, B, A
  43. 43. 余談その1:特殊相対性理論 基準系によって見る順番が異なる A B C A, B, C C, B, A
  44. 44. 唯一の正しいタイムラインの無さ • 特殊相対性理論 – 各基準系によって順番が異なる
  45. 45. 唯一の正しいタイムラインの無さ • 特殊相対性理論 – 各基準系によって順番が異なる • マルチスレッド処理 – スレッドによって観察する順番が異なる
  46. 46. メモリモデル 定義その2 • 開発者が頼ってもいい振る舞いを明確にする
  47. 47. メモリモデル 定義その2 • 開発者が頼ってもいい振る舞いを明確にする • プラットフォームがやってもいい最適化を制限 する
  48. 48. 歴史
  49. 49. Java Memory Model (JMM) • Write once, run anywhere • 1995 • 言語仕様(JLS)の一部 • Happened-before picture: Peter Campbell [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC BY-SA 4.0-3.0-2.5-2.0-1.0 (http://creativecommons.org/licenses/by-sa/4.0-3.0-2.5-2.0-1.0)]
  50. 50. happened-before
  51. 51. Leslie Lamport氏 • LaTex • happened-before picture: Leslie Lamport [GFDL (http://en.wikipedia.org/wiki/GFDL]
  52. 52. happened-before void hoge5() { a = 1; b = 2; c = 3; d = 4; e = 5; a = a + 1; }
  53. 53. happened-before void hoge4() { data = 42; ready = true; } void hoge3() { while (!ready) {}; assert data == 42; }
  54. 54. happened-before void hoge4() { data = 42; ready = true; } void hoge3() { while (!ready) {}; assert data == 42; }
  55. 55. happened-before void synchronized hoge4() { data = 42; ready = true; } void synchronized hoge3() { while (!ready) {}; assert data == 42; } 警告:hoge3 が先に実行されるとデッドロックが発生する
  56. 56. happened-before void synchronized hoge4() { data = 42; ready = true; } void synchronized hoge3() { while (!ready) {}; assert data == 42; } 警告:hoge3 が先に実行されるとデッドロックが発生する
  57. 57. JMM 仕様
  58. 58. 元 JMM のキーワード • synchronized – 排他制御 (mutual exclusion) – happened-before
  59. 59. 元 JMM のキーワード • synchronized – 排他制御 (mutual exclusion) – happened-before • volatile – 値の可視性
  60. 60. 元 JMM の問題点 • volatileが happened-before を成立しない • final の値が変わる • 有利な最適化方法が禁じられていた
  61. 61. Doug Lea氏 • Java のマルチスレッド の聖書の執筆 • High-level の並行処理 の Java ライブラリを公 開した
  62. 62. Java SE 5.0 • 現代の JMM • Lea氏の並行ライブラリが追加される picture: Zvi Roger [CC BY 3.0 (http://creativecommons.org/licenses/by/3.0)]
  63. 63. 現代の JMM • JSR-133 • 元 JMM の問題点を解決 – volatile が happens-before を成立 – final の値が変わらない
  64. 64. 現代 JMM のキーワード • synchronized – 排他制御 – happened-before • volatile – 値の可視性 – happened-before • final – イミュータブル
  65. 65. volatile != atomic volatile int id = 0; int incID() { return id++; }
  66. 66. JSR-133 の volatile void hoge4() { data = 42; ready = true; } void hoge3() { while (!ready) {}; assert data == 42; } 警告:hoge3 が先に実行されるとデッドロックが発生する volatile boolean ready = false;
  67. 67. happened-before • ロックの取得・開放 • volatile 読み込み・書き込み • final “freeze” (コンストラクタ) • 外部処理 (JNI) – System.out.println() – 入出力 • スレッド start()/join() • j.u.concurrent の collections の操作
  68. 68. java.util.concurency • JSR-166 • Doug Lee 氏のライブラリを導入
  69. 69. 並行処理の制御 • java.util.concurency • synchronized – wait()/notify() • volatile / final 抽象的 具体的
  70. 70. Fork/Join (JDK 7)
  71. 71. 関数型プログラミング(JDK 8) • ラムダ式 • Stream API λ
  72. 72. 実装
  73. 73. 余談その2:HSDIS • JITが生成するコードの可視化 • 逆アセンブラのプラグインが必要 – GNU binutils ベース – base-hsdis • コマンドライン引数 – +PrintAssembly – +CompileCommand=print,*MyClass.myMethod
  74. 74. Demo
  75. 75. 将来
  76. 76. JEP-188/JMM9 • JVM レベルの仕様 • C11/C++11のモデルとの互換性 • JDK 6以降の新機能を含む – (例AtomicX.weakCompareAndSet())
  77. 77. まとめ
  78. 78. 高いレベルの抽象化を利用する • java.util.concurency • synchronized – wait()/notify() • volatile / final 抽象的 具体的
  79. 79. 仕様に対して開発する • 稀にしか発生しない問題が多い • JRE や プラットフォームによって変わる • 避けるべき行為 – synchronized (new Object()) { } – 動くようになるまで闇雲に volatile を追加する
  80. 80. テストの方針 • 出来るだけ本番環境と近い環境でテストする – 同じハード – 同じ JRE (バージョンも) – 同じ設定
  81. 81. Java Concurrency in Practice • Java 並行処理の聖書 • JSR-133 もカバー
  82. 82. まとめ • 高いレベルの抽象化を利用する • 仕様に対して開発すること • テストは不可欠 • JCiP を読むこと
  83. 83. ありがとうございます!
  84. 84. 参照 • [ JSR 133 (Java Memory Model) FAQ ] https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html • [ Java Concurrency in Practice ] http://jcip.net/ • [ Concurrent Programming in Java ] http://gee.cs.oswego.edu/dl/cpj/ • [ The JSR-133 Cookbook for Compiler Writers ] http://gee.cs.oswego.edu/dl/jmm/cookbook.html • [ PrintAssembly ] https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly • [ BASIC DISASSEMBLER PLUGIN FOR HOTSPOT DOWNLOADS ] https://kenai.com/projects/base-hsdis/downloads

×