javaのデッドロックを実現するコードの例


何がロックですか
まずこのような生活の例を見てみましょう。川に橋があります。橋の幅が狭いので、車が一台しか通れません。車を並行させることができません。もし2台の自動車AとBがそれぞれ橋の両端からこの橋を通っていると、A車にとっては橋の左側のしばらくの道(つまり橋の一部の資源を占有しています)を通ります。橋を渡るにはB車が右側の橋を譲るのを待つ必要があります。この時A車は前に進めません。B車にとっては、橋の右側の道(つまり橋の一部の資源を占有しています)を通ります。橋を渡るにはA車が左の橋を譲るのを待つ必要があります。この時B車も前に進めません。両方の車がバックしないので、お互いの橋渡しを待っていますが、誰も道を譲らないと、いつまでも待ち続けます。この現象はロックです。もし自動車をプロセスに比べて、橋の面を資源とするなら、上述の問題はプロセスAが資源R 1を占有し、プロセスBが占有する資源Rrを待つと説明します。プロセスBはリソースRrを占有し、プロセスAが占有するリソースR 1を待つ。そして、リソースR 1とRrは、一つのプロセスのみを占有することができます。すなわち、二つのプロセスが同時に占有されてはいけません。その結果、二つのプロセスは実行できなくなり、他の措置を取らないと、このような循環待ち状況は無期限に持続し、プロセスのデッドロックが発生します。
コンピュータシステムでは、ソフトウェアに関連して、ハードウェアリソースがデッドロックされる可能性があります。例えば、システムの中にCD-ROMドライブとプリンターが一台しかありません。あるプロセスはCD-ROMドライブを占有しています。また、プリンタを申請します。もう一つのプロセスはプリンターを占有しています。CD-ROMも申請しています。結果として、両方のプロセスがブロックされ、永遠に自分で解除することはできません。
デッドロックとは、複数のプロセスが循環して相手の占有する資源を待って無期限に対峙し続ける局面を指す。明らかに、外力の作用がないと、デッドロックに関わる各プロセスは永遠に封鎖状態になります。上記の例から分かるように、コンピュータシステムのデッドロックの根本的な原因は資源が限られ、操作が不適切であることです。つまり、一つの原因はシステムが提供する資源が少なすぎて、合併プロセスの資源に対する需要を満たすことができないからです。このような競争資源によるデッドロックは私たちが議論する核心である。例えば、メッセージは一時的なリソースである。ある時点で、プロセスAはプロセスBからのメッセージを待っています。プロセスBはプロセスCからのメッセージを待っています。プロセスCはプロセスAからのメッセージを待っています。メッセージが来ないと、A、B、Cの3つのプロセスが前に進められなくなり、プロセス通信上のデッドロックが発生します。もう一つの原因は、プロセスの進行順序が不適切であることによるデッドロックです。資源が少ないからといって、必ずしもロックが生じるとは限らない。二人が丸木橋を渡るように、もし二人が先に渡らなければならないならば、丸木橋の上で頑固に持ちこたえて後戻りしないと、必ず競争資源にデッドロックが生じるはずです。しかし、もし二人が橋に上がる前に相手のいない人が橋の上にいるのを見て、相手のいない人が橋の上にいる時に自分が橋に上がったら、問題は解決されます。そのため、もしプログラムの設計が不合理であれば、進行の順序が不適切であれば、デッドロックが発生します。
デッド・ロック
t 1スレッドがO 1を占有していて、ちょうどo 2が必要であり、t 2はこの時O 2を占有していて、ちょうどo 1も必要としている時にのみ、デッドロックが発生します。
以下のコードt 1スレッドはo 1を占有し、o 2オブジェクトを取得するとo 1が解放され、t 2スレッドはo 2を占有してo 1を取得するが、このときo 1はt 1スレッドによって占有され、o 2はt 2スレッドによって占有され、t 1とt 2は無限に待機しており、デッドロックが発生する。

package javasimple;
/**
 *   demo
 * @author haokui
 *
 */
public class DieSynchronized {
 public static void main(String[] args) {
  /**
   *          t1、t2。        o1、o2    
   */
  Object o1 = new Object();
  Object o2 = new Object();
  Thread t1 = new Thread(new T1(o1,o2));
  Thread t2 = new Thread(new T2(o1,o2));
  t1.start();
  t2.start();
 }
}
//       
class T1 implements Runnable {
 Object o1;
 Object o2;
 public T1(Object o1, Object o2){
  this.o1 = o1;
  this.o2 = o2;
 }
 public void run() {
  // o1 o2
  synchronized (o1) {
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   synchronized (o2) {
    System.out.println("o2");
   }
  }
 }
}
class T2 implements Runnable {
 Object o1;
 Object o2;
 public T2(Object o1, Object o2){
  this.o1 = o1;
  this.o2 = o2;
 }
 public void run() {
  synchronized (o2) {
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   synchronized (o1) {
    System.out.println("o1");
   }
  }
  
 }
}
注意:o 1とo 2だけが共有されている場合にのみ合併が発生します。2つのオブジェクトは構造関数で共有できます。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。