Java では、デッドロックとは、スレッド 1 がスレッド 2 によって取得されるオブジェクト ロックを待機し、スレッド 2 がスレッド 1 によって取得されるオブジェクト ロックを待機するマルチスレッドの状況です。ここでは、スレッド 1 とスレッド 2 の両方がお互いを待機します。ロックを解除します。 Java のマルチスレッド プログラムでは、前述のオブジェクトにリンクされたモニターまたはロックを待機している間に、キーワード synchronized が実行中のスレッドをブロックするため、デッドロックが発生する可能性があります。次のセクションでデッドロックの仕組みと例を見てみましょう。
無料ソフトウェア開発コースを始めましょう
Web 開発、プログラミング言語、ソフトウェア テスト、その他
前述したように、同期メソッドはコードの特定の部分をロックできます。 Java のオブジェクトごとにロックが存在します。同期とは、関数またはコード ブロックをロックして、一度に 1 つのスレッドのみがその関数またはコード ブロックにアクセスできるようにする手法です。
特定のスレッドが同期関数を実行する必要がある場合、最初にロックの取得を試みます。同時に、別のスレッドがすでにロックを受信している場合、最初のスレッドはスレッド 2 がロックを解放するまで待機します。同期によってデータの不整合の問題は防止されますが、同期の問題は発生します。
「スレッド 1」と「スレッド 2」という 2 つのスレッドがあると仮定します。スレッド 1 はオブジェクト 1 のロックを取得し、スレッド 2 はオブジェクト 2 のロックを取得しました。メソッド 1 を実行するスレッド 1 は、オブジェクト 2 のロックを取得しようとしています。ただし、スレッド 2 はすでにオブジェクト 2 のロックを取得しています。
さらに、スレッド 2 もオブジェクト 1 のロックを取得する必要があります。ただし、スレッド 1 はオブジェクト 1 をロックしています。ここでは、スレッド 1 とスレッド 2 の両方が実行を完了できず、ロックを永遠に待ちます。この状況はデッドロックと呼ばれます。
言及されている例を以下に示します:
デッドロックを実装する Java プログラム。
コード:
public class DeadLockExample { //main method public static void main(String[] args) throws InterruptedException { //create three objects 1, 2 and 3 Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); //create three threads 1, 2 and 3 Thread th1 = new Thread(new SynchronizationThread(o1, o2), "thread 1"); Thread th2 = new Thread(new SynchronizationThread(o2, o3), "thread 2"); Thread th3 = new Thread(new SynchronizationThread(o3, o1), "thread 3"); //start thread 1 th1.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); //start thread 2 th2.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); //start thread 3 th3.start(); } } class SynchronizationThread implements Runnable { private Object o1; private Object o2; public SynchronizationThread(Object o1, Object o2){ this.o1=o1; this.o2=o2; } //function run @Override public void run() { //store the name of the thread String nm = Thread.currentThread().getName(); System.out.println( nm + " attaining lock on "+ o1 ) ; synchronized (o1) { System.out.println( nm + " attained lock on "+ o1 ) ; work(); System.out.println( nm + " attaining lock on "+ o2 ) ; synchronized (o2) { System.out.println( nm + " attained lock on "+ o2 ); work(); } System.out.println( nm + " released lock on "+ o2 ) ; } System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " completed execution.") ; } //function work private void work() { try { //thread sleeps Thread.sleep(30000); } //catch the exception catch (InterruptedException exc) { exc.printStackTrace(); } } }
出力:
このプログラムでは、実行中の 3 つのスレッドがリソースを共有し、オブジェクト 1 のロックを取得するように実行されますが、オブジェクト 2 のロックを取得しようとすると待機状態になります。デッドロックを防ぐには、コードを次のように書き換えます。
コード:
public class DeadLockExample { public static void main(String[] args) throws InterruptedException { Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); Thread th1 = new Thread(new SynchronizationThread(o1, o2), "thread 1"); Thread th2 = new Thread(new SynchronizationThread(o2, o3), "thread 2"); Thread th3 = new Thread(new SynchronizationThread(o3, o1), "thread 3"); //start thread 1, 2 and 3 th1.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); th2.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); th3.start(); } } class SynchronizationThread implements Runnable{ private Object o1; private Object o2; public SynchronizationThread(Object o1, Object o2){ this.o1=o1; this.o2=o2; } //function run @Override public void run() { //store the name of the thread String nm = Thread.currentThread().getName(); System.out.println( nm + " attaining lock on "+ o1 ) ; synchronized (o1) { System.out.println( nm + " attained lock on "+ o1 ) ; work(); } System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " acquiring lock on " + o2 ); synchronized (o2) { System.out.println( nm + " attained lock on "+ o2 ); work(); } System.out.println( nm + " released lock on "+ o2 ) ; System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " completed execution.") ; } //function work private void work() { try { //thread sleeps Thread.sleep(30000); } //catch the exception catch (InterruptedException exc) { exc.printStackTrace(); } } }
出力:
次に、デッドロック状況を回避するのに役立つガイドラインを示します。
ネストされたロックは、デッドロックを引き起こす一般的な原因の 1 つです。デッドロックを避けるために、すでにリソースを保持している場合は別のリソースをロックしないでください。ユーザーが 1 つのオブジェクトだけを操作する場合、デッドロックが発生することはあり得ません。
必要なリソースのみをロックすることをお勧めします。ただし、一部のユーザーは、必要でない場合でもリソースをロックしようとする場合があります。
2 つのスレッドがスレッド結合の助けを借りて互いの完了を無限に待機すると、デッドロックが発生します。スレッドが他のスレッドが完了するまで待機する必要がある場合は、スレッドが完了するまで待機する最大時間を指定して join を使用することをお勧めします。
以上がJava でのデッドロックの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。