はじめてのJava ~デッドロックと協調編~
スポンサーリンク
今回はマルチスレッドで起こり得るデッドロックとその解決法について説明します。
これを理解しないとプログラムの停止などに繋がるのでしっかり覚えましょう。
デッドロックが起こる場面
次のプログラムはデッドロックを起こします。
class X { Y y; synchronized void x1() { System.out.println("x1"); y.y2(); } synchronized void x2() { System.out.println("x2"); } }
class Y { X x; synchronized void y1() { System.out.println("y1"); x.x2(); } synchronized void y2() { System.out.println("y2"); } }
class ThreadX extends Thread { X x; ThreadX(X x) { this.x = x; } public void run() { for(int i = 0; i < 100000; i++) { x.x1(); } } }
class ThreadY extends Thread { Y y; ThreadY(Y y) { this.y = y; } public void run() { for(int i = 0; i < 100000; i++) { y.y1(); } } }
class Deadlock { public static void main(String args[]) { X x = new X(); Y y = new Y(); x.y = y; y.x = x; ThreadX tx = new ThreadX(x); ThreadY ty = new ThreadY(y); tx.start(); ty.start(); try { tx.join(); ty.join(); } catch(Exception e) { e.printStackTrace(); } System.out.println("end"); } }
// 出力 x1 y1
このプログラムを実行すると、デッドロックが起こり途中で止まります。
なぜなら、ThreadXはx1()メソッドを実行した後y2()メソッドを呼び出そうとしますが、ThreadYはx2()メソッドを呼び出そうとして待っているので、お互いが相手が終わるのを待ってしまうからです。
デッドロックの解決法
デッドロックを解決するにはスレッドの動作を協調させる必要があります。
協調にはwait()メソッドとnotify()メソッド、notifyAll()メソッドを使います。
wait()は現在のスレッドを待機させます。
引数で秒数(ミリ秒)を指定することもできます。
notify()とnotifyAll()はオブジェクトのロック開放を待機しているスレッドに通知を送ります。
notify()は1つのスレッドに、notifyAll()はすべてのスレッドに送ります。
Xクラスを以下のように変えてみましょう。
class X { Y y; synchronized void x1() { try { wait(); } catch(InterruptedException e) { e.printStackTrace(); } System.out.println("x1"); y.y2(); notify(); } synchronized void x2() { System.out.println("x2"); } }
Deadlock.javaを実行すると止まらくなりましたね。