Rainbow Engine

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

Java

デッドロックとライブロックとは?両者の違いやサンプルプログラムをご紹介

投稿日:2021年6月19日 更新日:

 

<目次>

(1) デッドロックとライブロックとは?両者の違いやサンプルプログラムをご紹介
 (1-1) デッドロック
  (1-1-1) 概要
  (1-1-2) サンプルプログラム
 (1-2) ライブロック
  (1-2-1) 概要
  (1-2-2) サンプルプログラム

(1) デッドロックとライブロックとは?両者の違いやサンプルプログラムをご紹介

(1-1) デッドロック

(1-1-1) 概要

デッドロックは複数のプロセスがお互いのリソースのロック解放を待っており、お互いが前に進めなくなっている状態を言います。
 
例えば次の図のように「プロセス①」が「リソース②」を使いつつ「リソース①」の解放を待っている状態で、逆に「プロセス②」が「リソース①」を使いつつ「リソース②」の解放を待っている状態とします。このような状態ではお互いがお互いの解放を待っているので、デッドロックが発生します。
 
(図111)イメージ図

 

デッドロックは多数のプロセスが同一のリソースを共有するような状況下で発生しうる問題になります。
 

(1-1-2) サンプルプログラム

●デッドロックを引きおこすクラス
スレッド「t1」は「someFunction1」を実行し、strAを占有してstrBが解放されたら、それらを合体させようとします。一方で、スレッド「t2」は「someFunction2」を実行し、strBを占有してstrAが解放されたら、それらを合体させようとします。この状況下だと、お互いがお互いを待って永遠に進まない「デッドロック」が発生します。
 
public class DeadLockSampleClass {

  private static String strA = "abcde";
  private static String strB = "fghij";

  public void someFunction1() {
    synchronized(strA) {
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("Thread#1 : strB の開放待ち");
      synchronized(strB) {
        String strC = strA + strB;
        System.out.println("Thread#1 : 完成品 = "+strC);
      }
    }
  }

  public void someFunction2() {
    synchronized(strB) {
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("Thread#2 : strA の開放待ち");
      synchronized(strA) {
        String strD = strA + strB;
        System.out.println("Thread#2 : 完成品 = "+strD);
      }
    }
  }

}
 
(補足)
synchronizedについては下記の記事を参照頂けたらと思います。
 
●上記を実行するmain文
 
public class DeadLockSample {

  static final DeadLockSampleClass dlock = new DeadLockSampleClass();
  public static void main(String args[]) {
    Thread t1 = new Thread(new Runnable() {
      public void run() {
        dlock.someFunction1();;
      }
    });
    t1.start();
    Thread t2 = new Thread(new Runnable() {
      public void run() {
        dlock.someFunction2();;
      }
    });
    t2.start();
  }
}

 

(図112)実行結果

 

上記プログラムを実行して、デッドロックが起きる様子を動画にしています。
 
(操作動画)

目次にもどる

(1-2) ライブロック

(1-2-1) 概要

ライブロックもデッドロックと非常に似ていますが、相違点としてライブロックに関係するプロセスは、相手の状態によって、自身の状態も定期的に変化していき、その結果としてお互いに進展しない状態を表しています。

有名?な現実世界の例えとして、二人の人が細い道ですれ違う際に、お互いに同じ方向に譲り合いを繰り返し、ぶつかりそうになりながら進めない状態ってありますよね?その状態がライブロックに似ています。

(図121)イメージ図
 

目次にもどる

(1-2-2) サンプルプログラム

●道を通るために相手(Bさん)に道を譲る「Aさん」
public class LiveLockPerson1 {
  //# 最初は「右」に避ける
  private boolean move_right = true; //# true=右側に避けた、false=左側に避けた
  //# 相手に道を譲るメソッド
  public void moveToPass(LiveLockPerson2 lp2) {
    while(this.move_right==lp2.hasMovedRight()) {
      try {
        Thread.sleep(1000);
        //# では、私が反対方向に避けますので、どうぞお通りくだだい
        System.out.println("「A」です。私が反対方向に避けますので、どうぞお通りください");
        this.move_right = moveOpposite(this.move_right);
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("「A」です。無事に通れました。");
  }
  //# どちらの方向に避けたかどうか?を教えるメソッド
  public boolean hasMovedRight() {
    //# true=右側に避けた、false=左側に避けた
    return this.move_right;
  }
  //# 反対方向に避けるメソッド
  public boolean moveOpposite(boolean isRight) {
    //# いま右なら左に避ける
    if(isRight==true) {
      return false;
    }
    //# いま左なら右に避ける
    else {
      return true;
    }
  }
}

●道を通るために相手(Aさん)に道を譲る「Bさん」
public class LiveLockPerson2 {
  //# 最初は「右」に避ける
  private boolean move_right = true; //# true=右側に避けた、false=左側に避けた
  //# 相手に道を譲るメソッド
  public void moveToPass(LiveLockPerson1 lp1) {
    while(this.move_right==lp1.hasMovedRight()) {
      try {
        Thread.sleep(1000);
        //# では、私が反対方向に避けますので、どうぞお通りくだだい
        System.out.println("「B」です。私が反対方向に避けますので、どうぞお通りください");
        this.move_right = moveOpposite(this.move_right);
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("「B」です。無事に通れました。");
  }
  //# どちらの方向に避けたかどうか?を教えるメソッド
  public boolean hasMovedRight() {
    //# true=右側に避けた、false=左側に避けた
    return this.move_right;
  }
  //# 反対方向に避けるメソッド
  public boolean moveOpposite(boolean isRight) {
    //# いま右なら左に避ける
    if(isRight==true) {
      return false;
    }
    //# いま左なら右に避ける
    else {
      return true;
    }
  }
}

●両者のスレッドを起動するmain文
public class LiveLockSample {

    static final LiveLockPerson1 lp1 = new LiveLockPerson1();
  static final LiveLockPerson2 lp2 = new LiveLockPerson2();
  public static void main(String args[]) {
    Thread t1 = new Thread(new Runnable() {
      public void run() {
        lp1.moveToPass(lp2);
      }
    });
    t1.start();
    Thread t2 = new Thread(new Runnable() {
      public void run() {
        lp2.moveToPass(lp1);
      }
    });
    t2.start();
  }
}
(図122)実行結果:「無限ループ」
お互いが道を譲りあい続け、結果的に無限ループになります。
 
上記プログラムを実行して無限ループする様子を以下の動画でご紹介しています。
(操作動画)
 

Adsense審査用広告コード


Adsense審査用広告コード


-Java

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

Servlet/JSPで日本語文字が「???」になる問題とFilterの活用について

(0)目次&概説 (1) 事象 (2) 原因 (3) 対処方法1  (3-1) フィルタクラスの新規作成  (3-2) フィルタクラスへのコード追加  (3-3) 疎通確認テスト (4) 対処方法2 …

Javaのアノテーションを自作する方法をご紹介(サンプルプログラム付き)

(1) 自作アノテーションの作成~使用の手順  (1-1) アノテーションの宣言  (1-2) メタアノテーションの追加(任意)  (1-3) アノテーションを実際に使う(注釈の付与)  (1-4) …

木構造の探索における計算量の違いや木構造の種類について(B木/二分木/2-3探索木)

<目次> (1) 木構造の探索における計算量の違いや木構造の種類について(B木/二分木/2-3探索木)  (1-1) 木構造について  (1-2) 「B木」構造  (1-3) 「二分木」構造  (1- …

getParameterとgetAttributeの違いやJSPからServletへの値の受け渡し

<目次> (1) getParameterとgetAttributeの違いやJSPからServletへの値の受け渡し  (1-1) 前半:request.getParameterについて   ●概要 …

EclipseでJavaプロジェクトを同一サーバ内で別名コピーする方法

(0)目次&概説 (1) プロジェクトの別名コピーの手順  (1-1) プロジェクトのコピー&ペースト  (1-2) コピーしたプロジェクトをTomcatへ登録  (1-3) Tomcatサーバの再起 …

  • English (United States)
  • 日本語
Top