woshidan's blog

そんなことよりコードにダイブ。

Java言語で学ぶデザインパターン入門[マルチスレッド編]を読みました

世の中には、RxJavaやIntentServiceといった初心者でも一応非同期処理を書けるライブラリはあるのですが、それでも隠しきれない理解不足を痛感したため、Java言語で学ぶデザインパターン入門[マルチスレッド編]を読みました。

実を言うと、以前に一度は目を通しています。

しかし、自分はそれだけではまだまだ理解が足りなかったので、ここ一ヶ月くらいかけて、ほとんどのサンプルコードを写経 & コンパイルして動かし、演習問題もほとんど解いて、それらの概要をこまごまGithubのプライベートリポジトリにまとめたり写経したりしてました*1

最初は2週間くらいでいけるかな、と思っていたところ章を追うにつれて重くなり、結局その倍の一ヶ月かかりました。

仕事が少し忙しくて一週間おいてしまったけれど大丈夫かな、と思いながら開始しても後の章に前の章の内容がしばしば登場するため忘れにくくて安心です。

途中から、本当は三ヶ月はかけてよかったかなという気配のあるところをゴリ押しで一ヶ月でやったためかなりしんどかったですが、

  • 自分が仕事で触れる範囲ではバックグラウンドと非同期処理が同じものを違う見方で言ったものだとわかる(ぇ
  • java.util.concurrentパッケージのクラス名を見て、何をしたいクラスなのか連想したり、調べたりすることができる
  • 非同期処理をラップしているAPIにたいして、メソッド名などから中で何をやっているのか見当がつく

ようになってきました。

そのため、安心してコード書ける範囲が少しは広がった気がします。実際コードを見て修正して処理が安定する部分が出てきたのでよかったです。

...これだけだと、後で読み返してだからなんだ、と言いたくなる気がするので、少しだけメモして終わります。

スレッドについて

  • 基本的に一つのスレッドはwhile文での繰り返しやif文での条件分岐はありつつもメソッドの範囲では上から下へ進みます
  • たくさんの処理をこなしていく時に
    • 単純に上から下への1つの流れで処理していく場合を逐次
    • 複数のスレッドで分割して同時に処理していく場合を並列
    • 複数のスレッドで分割したりしなかったり、順番が決まってなかったりする場合を並行といいます
  • 一般にマルチスレッド処理とかバックグラウンド処理とかいう場合は、以下に上手に並行処理を扱うか、という話をしています
    • 並行処理を上手に扱うというのは
      • データの整合性を守りつつ(安全性)
      • うまく分担して処理速度を上げつつ(パフォーマンス)
      • どこかで待ち合わせに失敗して処理が止まってしまったりしない(生存性)といったことが両立できてますか、という話だった気がします
  • スレッドは上から下へまっすぐ進む以外に
    • その場で決まった時間休んだり(sleep)
    • 特定のインスタンスについて行列に並んだり(wait)
    • 他のスレッドの処理が終わるまで待ったり(join)
    • 処理を中断したり(interrupt)します
  • データの守り方は
    • 複数のスレッドで共有するデータの変更に関しては基本的に複数のスレッドからアクセスさせない
    • 判断とその結果にもとづく実行は1つのスレッドにひと続きで行わせる
      • そのために、あるインスタンスメソッドを実行できる条件を満たすまでそのインスタンスのウェイトセットという行列に突っ込んで待たせる、という処理がよくあるらしいです(Guarded Suspension)
    • 特定のインスタンスに1つのスレッドしかアクセスできないと言った制約はsynchronizedで実装します
  • 自分はAという処理を先にしたいから、Bという処理は他のスレッドのインスタンスを立ち上げて(start)そちらにさせる、ということをよくします
    • 他のスレッドの処理の結果を受け取りたい場合は、Futureパターンを使います

Producer-Consumerが~とか、いろいろあったのですが、これ以上は、また本を読めばいいのかな、と思うので、ここまでで止めにします。

本の中身を吸収するだけ、という勉強の仕方をするとブログに書きにくいのですが、それで勉強する内容を縛るのは本末転倒ですし、こちらの勉強が個人的に重すぎてブログに書けるネタも書けていなかったりするため、忘れてしまう前にGWあたりでそれらをまとめていけるといいなと思っています。

*1:12-3は諦めてせこせこ写経しました...