JAva Synchronizedキーワードとデッドロック

4655 ワード

Synchronizedキーワード
簡単なコードを使ってスレッドの“デッドロック”を実現して、この問題はSynchronizedキーワードを試験します
Java言語のキーワードは、メソッドまたはコードブロックを修飾するために使用される場合、同じ時点で最大1つのスレッドだけがセグメントコードを実行することを保証します.
2つの同時スレッドが同じオブジェクトobjectのsynchronized(this)同期コードブロックにアクセスすると、1時間に1つのスレッドしか実行できません.別のスレッドは、現在のスレッドがこのコードブロックを実行するまで待たなければなりません.
しかしながら、あるスレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、別のスレッドはobject内の非synchronized(this)同期コードブロックにアクセスすることができる.
特に重要なのは、1つのスレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、他のスレッドがobject内の他のすべてのsynchronized(this)同期コードブロックへのアクセスがブロックされることです.
スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる.その結果、objectオブジェクトのすべての同期コード部分への他のスレッドのアクセスが一時的にブロックされる.
package multithread_learning;
/** 
* @author xiaohao 	
* @date     :Aug 7, 2017 3:11:26 PM 
* @version 1.0   
*/
public class TestSynchronized {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Sy sy = new Sy(0);
	        Sy sy2 = new Sy(1);
	        sy.setName("t1");
	        sy2.setName("t2");
	        sy.start();
	        sy2.start();
	}
}
class Sy extends Thread {
    private int flag ;

    static Object x1 = new Object();
    static Object x2 = new Object();

    public Sy(int flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        System.out.println(flag);
        try {
            if (flag == 0) {
                synchronized (x1) {
                    System.out.println(flag+"   x1");
                    Thread.sleep(1000);
//                    x1.wait(1000);
                    synchronized (x2) {
                        System.out.println(flag+"   x2");
                    }
                    System.out.println(flag+"   x1 x2");
                }
            }
            if(flag == 1) {
                synchronized (x2) {
                    System.out.println(flag+"   x2");
                    Thread.sleep(100);
//                    x2.wait(100);
                    synchronized (x1) {
                        System.out.println(flag+"   x1");
                    }
                    System.out.println(flag+"   x1 x2");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

このプログラムが実行されると、x 1はx 2を待っているため、x 2はx 1を待っているため、硬直状態になり、デッドロックが発生する.
この時、少し修正して、私はThreadクラスのsleep方法を使わないで、Objectクラスのwait方法を変えて、この時デッドロックが発生しないで、これもwaitとsleepの違いを検証しました:
waitメソッドは現在のオブジェクトのロックを解放しますが、sleepメソッドは現在のオブジェクトのロックを解放しません.
package multithread_learning;
/** 
* @author xiaohao 	
* @date     :Aug 7, 2017 3:11:26 PM 
* @version 1.0   
*/
public class TestSynchronized {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Sy sy = new Sy(0);
	        Sy sy2 = new Sy(1);
	        sy.setName("t1");
	        sy2.setName("t2");
	        sy.start();
	        sy2.start();
	}
}
class Sy extends Thread {
    private int flag ;

    static Object x1 = new Object();
    static Object x2 = new Object();

    public Sy(int flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        System.out.println(flag);
        try {
            if (flag == 0) {
                synchronized (x1) {
                    System.out.println(flag+"   x1");
//                    Thread.sleep(1000);
                    x1.wait(1000);
                    synchronized (x2) {
                        System.out.println(flag+"   x2");
                    }
                    System.out.println(flag+"   x1 x2");
                }
            }
            if(flag == 1) {
                synchronized (x2) {
                    System.out.println(flag+"   x2");
//                    Thread.sleep(100);
                    x2.wait(100);
                    synchronized (x1) {
                        System.out.println(flag+"   x1");
                    }
                    System.out.println(flag+"   x1 x2");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
0
1
1   x2
0   x1
1   x1
1   x1 x2
0   x2
0   x1 x2

スレッドt 1とt 2は、どちらのスレッドが先に実行されるとは限らないので、3,4行目の位置が入れ替わる場合があるかもしれないが、flag=0の場合、x 1オブジェクトwaitの時間は1000 msであり、このときx 1のオブジェクトロックが解放され、終了を待つ(つまり1000 ms以内)、flag=1の条件がx 2およびx 1オブジェクトを実行済みとなり、このときflag=0はx 1オブジェクトを実行し続け、つまり、常に1リリース、0リリースです.
ただしwait()メソッドとnotify()メソッドは同期コードブロックにしか入れられません.同期コードブロックで使用しない場合、コンパイル時にエラーは発生しませんが、実行時にjava.lang.I llegalMonitorStateException異常が放出されます.