スレッド同時synchronized

5388 ワード

synchronizedキーワードはjavaにおけるスレッドが原子性を同時に保証する方法である.
  • 反発ロック
  • 再入ロック
  • ロックされたオブジェクトは、スタック上のオブジェクト
  • です.
  • コードブロック上、方法上、静的方法上
  • 異常上自動レリーズロック
  • synchronizedの使い方
    public class SeaTiger implements Runnable {
        Object o = new Object();
        @Override
        public void run() {
            synchronized (o) {
                System.out.print(Thread.currentThread().getName() + " ");
                for (int i = 0; i < 5; i++) {
                    System.out.print(i + " ");
                }
                System.out.println();
            }
        }
    
        public static void main(String[] args) {
            SeaTiger seatiger = new SeaTiger();
            for(int i=0; i<3; i++) {
                new Thread(seatiger, "seatiger" + i).start();
            }
        }
    }

    上記のコードでは、synchronized (o)がロックするのはoという参照実行スタックメモリの真のオブジェクトである.runメソッドを実行する5つのスレッドが同時に実行され、どのスレッドが先にロックを取得して先に実行するか、他のスレッドはスレッド解放ロックを実行するのを待たなければならない.その取得ロック、どの実行
    実行結果seatiger 0 0 1 2 3 4 seatiger 2 0 1 2 3 4 seatiger 1 0 1 2 3 4
    mainメソッドのテストプログラムの変更
    public static void main(String[] args) {
            SeaTiger seatiger = new SeaTiger();
            SeaTiger seatiger2 = new SeaTiger();
            for(int i=0; i<3; i++) {
                new Thread(seatiger, "1seatiger" + i).start();
            }
            for(int i=0; i<3; i++) {
                new Thread(seatiger2, "2seatiger" + i).start();
            }
        }

    実行結果1 seatiger 0 2 seatiger 1 0 0 1 2 3 4 1 seatiger 2 1 0 2 3 2 4 1 seatiger 1 0 1 2 2 seatiger 2 0 1 2 2 3 4 4 4 4 4 2 seatiger 0 1 2 3 4 4
    2回目の結果が乱れ、原因分析は1つ目のmainメソッドではSeaTiger seatiger = new SeaTiger();が1回のみオブジェクトを作成し、対応するnew Object();も1回のみなので、最初から最後まで1つのロックしかありません.2つ目のテストメソッドでは、2つのオブジェクトを作成するとともに、2つのロックを作成し、各オブジェクトが自分のスレッドタスクを実行する場合、自分の必要な鍵を探します.だからseatigerseatiger2は互いに鍵をかけられません.
    複数のオブジェクトが互いにロックされている場合、同じロックのうちの1つを取得することを保証すれば、インデックスによって取得されたオブジェクトを単一のモード`static Object oに設定することができる.
    static {
        o = new Object();
    }`

    これにより、oが指すオブジェクトが単列であることが保証され、複数の異なるオブジェクトの実行スレッドが同じロックテストの第2の方法1 seatiger 0 1 2 3 4 2 seatiger 1 0 1 2 3 4 4 1 seatiger 2 0 1 2 3 4 1 seatiger 2 0 1 2 3 4 1 seatiger 1 0 1 2 3 4 2 seatiger 0 1 2 2 3 4
    ロックされたコードが速いか方法ではないことを再宣言します. 作用方法上synchronizedキーワードは、メソッドにも使用できます.
        public synchronized void run() {
            
        }

    このように書き込みロックされているのは、自身のオブジェクトthisであり、seatigerおよびseatiger2自身が指しているオブジェクトがsynchronized(this)に相当する
    作用静的方法上synchronizedドメイン静的メソッドに適用可能
    public synchronized static void m() {
    }

    アクティブドメイン静的メソッドでロックに相当するのはclassオブジェクトsynchronized(T.class)です.
    各クラスにはclassオブジェクトが1つしかないため、オブジェクトがスレッドを起動しても、取得と同時に同じハンドルを取得しても、単列オブジェクトのロックを取得しても、効果は同じです.
    ダーティリード問題(dirtyRead)、書き方にロックをかけ、読み方にロックをかけない
    public class Seatiger {
        private String name;
        public synchronized void set() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.name = "langlihuge";
        }
        public String get(){
            return name;
        }
        
        public static void main(String[] args) throws Exception{
            Seatiger seatiger = new Seatiger();
            //     
            new Thread(()-> seatiger.set()).start();
            System.out.println(seatiger.get());
            Thread.sleep(300);
            System.out.println(seatiger.get());
        }
    }

    実行結果nulllanglihuge
    一つのロックをかけた方法に対して、読み方はロックをかけていない、読む時、読み取るかもしれない、書く方法の中で完全に処理したデータがない.
    リエントロック可能
    1つの同期方法は別の同期方法を呼び出すことができて、1つのスレッドはすでにあるオブジェクトのロックを持っていて、再び申請する時依然としてそのオブジェクトのロックを得ることができます.つまりsynchronizedで得たロックは再入力可能な注意です:2つの同期方法の中で ..このロックは、1つのフラグ記録があって、1つが別のロックを調整するならば、このロックのこのフラグは2です
    第一のケース
    public class Seatiger {
        synchronized void f1() throws Throwable{
            System.out.println("f1 start()...");
            TimeUnit.SECONDS.sleep(1);
            f2();
        }    
        synchronized void f2() throws Throwable{
            TimeUnit.SECONDS.sleep(3);
            System.out.println("f2 start()...");
        }    
        public static void main(String[] args) {
            new Thread(()-> {
                try {
                    new Seatiger().f1();
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    f 1ではf 2のメソッドが呼び出され、ロックは同じですが、呼び出すことができ、再入力できます.
    第2のケース継承で発生する可能性のあるケース、
    public class T {
        synchronized void m() {
            System.out.println("m start");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("m end");
        }
        
        public static void main(String[] args) {
            new TT().m();
        }    
    }
    class TT extends T {
        @Override
        synchronized void m() {
            System.out.println("child m start");
            super.m();
            System.out.println("child m end");
        }
    }

    ここは なので、同じ鍵です
    同期メソッドに異常が発生すると、ロックが解除されます
    プログラムは実行中、異常が発生した場合、try、catch処理がなく、デフォルトでロック、他のスレッドを解放し、ロックリソースを奪い続けます.