JJUG ナイト・セミナー「Javaパラレル処理の最前線」に参加してきた。 #jjug

9月17日にJJUG ナイト・セミナー「Javaパラレル処理の最前線」に参加してきました。

申し込み開始の次の日?に申し込んだのですがキャンセル待ち43人目という人気っぷり。
とは言え、大体キャンセルが多く出るので余裕かと思っていたのですが、
開始2時間前になんとかいうギリギリでの参加になりました。

  • タイムスケジュール
19:00- 櫻庭祐一さん (@skrb): Legend of Java Concurrency/Parallelism
19:25- 槙俊明さん (@making): そんなリザルトキャッシュで大丈夫か?
19:50- 休憩
20:00- 久保智さん: Java EEでの話(仮)
20:25- きょんさん (@kyon_mm): Groovyで学ぶプロセス代数
20:50- 谷本心さん (@cero_t): LT: Parallel Streamを真面目に勉強してみた話

櫻庭祐一さん (@skrb): Legend of Java Concurrency/Parallelism

Javaの歴史
  • Java 1.0
    • Thread/Runnnable
    • synchronized
    • volatile
    • Object#wait など。
    • この時期は処理を切り替えて走らせていたのでコアが遊んでしまう。
  • 1.1
    • 匿名クラスが書けるようになった。

new Thread()なんて使ってる人いないですよね!

  • 1.4
    • Mostly Concurrent
    • Mark & Sweep GC
  • 5
    • Async Execution
      • Concurrency Utilities
      • Executor / ExecutorService
      • Runnnable / Callable
      • Future
    • Synchronizer
      • ReentrantLock
      • Semaphore
      • CountDownLatch
    • Threadsafe Collection
      • BlockingQueue
      • ConcurrentHashMap
      • CopyOnWriteArrayList
    • Atomic Operation
      • AtomicInteger
      • AtomicReference
  • 7
    • Multi Coreの時代になって、細かいタスクを色んなコアにばらまいて実行する。細かいから同期のコストも小さい。
    • ただ、forl/joinは書くのが面倒くさい!
  • 8
    • Project Lambda
    • ParallelStream
    • Spliterator
まとめ
  • 設計的にはThreadは独立。
  • タスクは細かくすることで同期のコストも少なくなる。

槙俊明さん (@making): そんなリザルトキャッシュで大丈夫か?

  • ここでいうリザルトキャッシュ。
  • 重い処理の結果を格納するメモリ

  • Java並行処理プログラミング」という本の内容を話す。
    • Twitterではいい本なんだけど5時代なので、最新版が欲しいとの声多数。。。
たまに見る実装の話
  • キャッシュをHashMapに突っ込む。(HashMapはスレッドセーフじゃないので×)
    • ConcurrentHashMapに変更する。
    • 実はキャッシュをうまく使えてない
    • getしてる段階ではまだputされていないので、キャッシュがうまく使えていない
  • FutureTaskを使って遅延評価
    • とりあえず最初にput。
    • 新しいFutureTaskで上書きされた。
    • FutureTaskをputする方法は本ではほとんど正解に近いと書かれているが、実際にやってみると全然ダメw
  • putではなくputIfAbsentメソッドを使う。
    • キーが存在しない場合はnullを、そうでない場合は入っているモノを返す。
    • 処理は1回しか行われず、正しくキャッシュされている。

  • Java8から
    • ConcurrentHashMapのcomputeIfAbsentメソッドが追加。
    • Mapに値が入っていなかったらラムダ式を実行する。

まとめ
  • ConcurrentHashMap#putIfAbsent + FutureTaskを使う。
  • 8からは
    • ConcurrentHashMapのcomputeIfAbsentメソッドを使う。
  • GoogleのguavaのMapMakerが色々便利らしい。
  • JavaEE8のJCash?とかいうのがいいらしい。

20:00- 久保智さん: Java EEでの話(仮)

元はLTで発表した内容と言うことで早かったので内容を適当にまとめ。

  • レガシー枠との事。
  • Java EEの昔話
  • 並行処理でハマった内容
JavaEEの昔の話。
  • 並行処理は難しい。
    • SingleThreadModel → スレッドセーフになっていない。
    • 現在は非推奨
  • JavaEEの仕様を決める人でも間違えることがあるので、どんどん失敗しましょう
SimpleDateFormat
  • 昔はJavaDocにスレッドセーフでないと記載されていなかった!(今は記載されている)
  • JavaDocにスレッドセーフと書いてないものはスレッドセーフではない!!

System.out
  • 複数スレッドから同時に書き込むとブロックする
    • ログ出力ライブラリを使いましょう

Servletのスコープ
  • HttpSessionスコープにはハマる。
  • ブラウザ単位で同時にアクセスされる可能性がある。
  • アクセス時には安全のためロックしましょう
  • ロックできない箇所がある。
    • HttoSession#invalidate()
    • セッションを破棄するメソッド。
    • Tomcatだと実装を直接扱えば破棄されているかを判定するメソッドがある。
JSF/CDIの場合
  • 複数スレッドからの同一オブジェクトへのアクセスはブロックされている。
  • 何でもかんでもSingletonにすると逆に性能劣化が。
  • スコープは適切に扱いましょう。
Ejb
  • Stateless SessionBean
    • 状態を持たないSeessionBean
  • コンテナのプールにもつ事で同じインスタンスに複数スレッドから同時にアクセスされることはない
  • コンテナのプールはデフォルトでは無効化されていることが多いので開発環境では毎回インスタンスが生成されている
  • 本番に乗せた途端複数のスレッドで使いまわされてハマる。
  • Stateless SessionBeanに状態を持たせるのはやめましょう。
JPAのキャッシュ
  • PKの比較を比較することでキャッシュされているか判別する。
  • その比較に時間がかかると、キャッシュすることで遅くなることがある。
  • JPAの楽観ロック
  • @versionアノテーションを付けるだけで楽観ロックができる。
  • 複数スレッドからの同時更新を防ぐ
  • JPQLからのupdateでは楽観ロックが有効にならない
  • L2キャッシュは性能が問題にならない限り切っておきましょう
CDIの非同期処理
  • @Asynchronousを付けるだけで非同期処理になる。
  • 簡単だけど障害時を考えるとそれでよいのか。
  • 簡単に使えるからといってすぐ何でもかんでも使うのではなく、よく考えて使いましょう。

20:25- きょんさん (@kyon_mm): Groovyで学ぶプロセス代数

  • CSPというと怖いように思うが、こうやって触っていけばいいんだよね。というようにしたい。
  • CSPとは、並行処理のモデルとして利用されているプロセス代数の一例。
    • 並行処理関連で「チャネル」が云々とか言われたらCSPかな?って思って聞くといいかも。
  • 研究者と実績がたくさん
  • Java、Groovyで使用可能。
  • 逐次実行と平行実行の比較
    • 逐次実行だったらあまり間違わないところでも、平行実行にするだけで難しくなることがよくある。
  • FDRというツールで、CSPとほぼ同等の記法のスクリプトを書くと検証してくれる。
    • 最初に逐次実行で書いて、並列で書くとどの程度同一か判定してくれる。
  • CSPをJava実装したものがJCSPというライブラリとして公開されていて、GParsはJCSPをラップしている。
  • Groovyの2.0からGParsは標準で入っている。

  • groovyx.gpars.云々パッケージにいい感じにクラスが定義されているのでこれらを使っていく。
    • JCSPはもっと色々あるけど、gparsがラップしてるのはこれくらい。
  • チャネルを通してでしかプロセス間でやりとりできない。

  • 正直、この後の内容は前提知識が足りなくて理解できず。
    • コードをたくさん載せてくれているので、動かせばわかるか?(探したけどスライドは公開されていない??TT)

  • チャネルは同期的に動作し、プロセスは非同期で動作する。電話みたいなもの(電話かけても相手が受け取らないと始まらない)

まとめ
  • CSPを使ってみるとかいうとハードルが高いけど、Gparsを使うと結構簡単に試せる。
  • モデルとコードが近くなりやすいCSPで書いておくとツールでの検証がはかどるし、
  • 検証してからコードに書くのも困らない。
  • 非同期処理のプロジェクトで失敗したのをキッカケに取り組み始めた。
    • 今はCSPベースの何かを開発している!
  • CIサーバ、テスティングフレームワーク、ビルドツールとかを作っている!

20:50- 谷本心さん (@cero_t): LT: Parallel Streamを真面目に勉強してみた話

  • Java8といえばStream。
    • Parallel Streamは面白い!
  • StreamAPIをパラレルで行えるのがParallel Stream
  • Parallel Streamにしても性能が出ない
    • 素数が少ないと性能がでない
    • 10万要素ぐらいを捌かないと効果がないと感じている。
    • 落とし穴はいっぱいある
    • Parallel Streamは例外時の挙動が予想できない。
    • 例外が発生しても、例外が発生したスレッド以外は実行する。
    • 例外が発生した時点で割り当てられている処理は行われるが、割り当てられていない処理は実行されない。
    • 一回の処理の中では例外が発生しないようにするか、例外をtrycatchして処理するようにしないと、色々ハマる。
    • ストリーム内でDBにアクセスするとかありえない。
    • それ以前にストリームの外にある変数にアクセスしたらダメ。