Androidマルチスレッド---同時および同期(synchronized)


一、錠


オブジェクトの組み込みロックとオブジェクトのステータスの間には内在的な関連はありません.ほとんどのクラスでは、組み込みロックが有効なロックメカニズムとして使用されていますが、オブジェクトのドメインは必ずしも組み込みロックによって保護されるわけではありません.オブジェクトに関連付けられた組み込みロックを取得すると、他のスレッドがオブジェクトにアクセスすることはできません.あるスレッドがオブジェクトのロックを取得した後、他のスレッドが同じロックを取得することはできません.各オブジェクトに内蔵ロックがあるのは、ロックオブジェクトを明示的に作成しないためです.
したがってsynchronizedは内蔵ロックのロックメカニズムにすぎず、あるメソッドにsynchronizedキーワードを付けると、内蔵ロックを取得してから実行できることを示し、他のスレッドアクセスが内蔵ロックを取得する必要がない方法を阻止することはできません.
JAva内蔵ロックは反発ロックであり、これは最大1つのスレッドだけがロックを取得できることを意味し、スレッドAがスレッドBが持つ内蔵ロックを取得しようとすると、スレッドAは待機またはブロックしなければならず、スレッドBがこのロックを解放しないことを知っていて、Bスレッドがこのロックを解放しなければ、Aスレッドは永遠に待機し、これは高同時システムにとって致命的である.
JAvaのオブジェクトロックとクラスロック:javaのオブジェクトロックとクラスロックは、ロックの概念上、基本的に内蔵ロックと一致していますが、2つのロックは実際には大きく異なり、オブジェクトロックはオブジェクトインスタンスメソッド、またはオブジェクトインスタンス、クラスロックはクラスの静的メソッドまたはクラスのclassオブジェクトに使用されます.クラスのオブジェクトインスタンスは複数ありますが、クラスごとにclassオブジェクトが1つしかないため、異なるオブジェクトインスタンスのオブジェクトロックは互いに干渉しませんが、クラスごとに1つのクラスロックしかありません.
Javaの各オブジェクトはロックとして使用できます.これはsynchronizedが同期を実現する基礎です.1.通常の同期方法で、ロックは現在のインスタンスオブジェクト2である.現在のクラスのclassオブジェクト3である静的同期方法.同期メソッドブロック、ロックはカッコ内のオブジェクト
 

以下説明する


synchronized修飾方法


synchronizedは静的方法を修飾し、


synchronized(this),


synchronized(クラス)、


synchronized(変数)の違い


 

二、修飾方法とコードブロック


修飾方法は、方法の前にsynchronizedを付け、synchronized修飾方法は1つのコードブロックを修飾するのと似ていますが、作用範囲が異なり、修飾コードブロックは括弧で囲まれた範囲であり、修飾方法範囲は関数全体です.

public synchronized void method()
{
   // todo
}

public void method()
{
   synchronized(this) {
      // todo
   }
}

synchronizedを使用してメソッドを定義できますが、synchronizedはメソッド定義の一部ではありません.したがって、synchronizedキーワードは継承できません.親クラスのメソッドでsynchronizedキーワードが使用され、子クラスでこのメソッドが上書きされている場合、子クラスのメソッドのデフォルトでは同期ではなく、子クラスのこのメソッドにsynchronizedキーワードを明示的に追加する必要があります.もちろん、子クラスメソッドで親クラスの対応するメソッドを呼び出すこともできます.これにより、子クラスのメソッドは同期ではありませんが、子クラスは親クラスの同期メソッドを呼び出すので、子クラスのメソッドも同期に相当します.この2つの方法の例コードは、サブクラスメソッドにsynchronizedキーワードを追加することです.
class Parent {
   public synchronized void method() { }
}
class Child extends Parent {
   public synchronized void method() { }
}

注意:
  • インタフェースメソッドを定義するときにsynchronizedキーワードを使用することはできません.
  • の構築方法ではsynchronizedキーワードは使用できませんが、synchronizedコードブロックを使用して同期できます. 

  • (一)オブジェクトロックのsynchronized修飾方法とコードブロック

    public class TestSynchronized {
        public void test1() {
            synchronized (this) {
                int i = 5;
                while (i-- > 0) {
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException ie) {
                    }
                }
            }
        }
    
        public synchronized void test2() {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    
        public static void main(String[] args) {
            final TestSynchronized myt2 = new TestSynchronized();
            Thread test1 = new Thread(new Runnable() {
                public void run() {
                    myt2.test1();
                }
            }, "test1");
            Thread test2 = new Thread(new Runnable() {
                public void run() {
                    myt2.test2();
                }
            }, "test2");
            test1.start();
            test2.start();
        }
    }
    
    test2 : 4
    test2 : 3
    test2 : 2
    test2 : 1
    test2 : 0
    test1 : 4
    test1 : 3
    test1 : 2
    test1 : 1
    test1 : 0

    上記のコードは、最初の方法ではコードブロックを同期する方法で同期され、入力されたオブジェクトインスタンスはthisであり、現在のオブジェクトであることを示している.もちろん、他のオブジェクトインスタンスを同期する必要がある場合は、他のオブジェクトのインスタンスも入力することができる.2つ目の方法は、方法を修飾する方法で同期することです.最初の同期コードブロックがthisに渡されるため、2つの同期コードに必要なオブジェクトロックはすべて同じオブジェクトロックである.mainメソッドでは、2つのスレッドをそれぞれ開き、test 1メソッドとtest 2メソッドをそれぞれ呼び出すと、2つのスレッドはオブジェクトロックを取得する必要があり、もう1つのスレッドは待たなければなりません.実行の結果も、test 2スレッドが実行されるまでロックが解除され、test 1スレッドが実行を開始しないことがわかります.
    test 2メソッドのsynchronizedキーワードを削除すると、実行結果はどうなりますか?test 1:4 test 2:4 test 2:3 test 1:3 test 1:2 test 2:2 test 2:1 test 1:1 test 2:0 test 1:0は実行結果であり、あるスレッドがオブジェクトロックを得たが、別のスレッドが同期していない方法やコードにアクセスできるため、出力が交互に行われていることがわかります.同期されたメソッド(ロックメソッド)と同期されていないメソッド(通常のメソッド)は互いに影響しません.1つのスレッドが同期メソッドに入り、オブジェクトロックが得られます.他のスレッドは同期されていないメソッド(通常のメソッド)にアクセスできます.

    (二)クラスロックの修飾(静的)方法とコードブロック

    public class TestSynchronized {
        public synchronized void test1() {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    
        public static synchronized void test2() {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    
        public static void main(String[] args) {
            final TestSynchronized myt2 = new TestSynchronized();
            Thread test1 = new Thread(new Runnable() {
                public void run() {
                    myt2.test1();
                }
            }, "test1");
            Thread test2 = new Thread(new Runnable() {
                public void run() {
                    TestSynchronized.test2();
                }
            }, "test2");
            test1.start();
            test2.start();
        }
    }
    
    test1 :4
    test2 :4
    test1 :3
    test2 :3
    test2 :2
    test1 :2
    test2 :1
    test1 :1
    test1 :0
    test2 :0

     


    上記のコードsynchronizedは静的メソッドとインスタンスメソッドを同時に修飾するが,実行結果は交互に行われ,クラスロックとオブジェクトロックは2つの異なるロックであり,互いに干渉しない異なる領域を制御していることを実証した.同様に、スレッドがオブジェクトロックを取得すると同時に、クラスロック、すなわち2つのロックを同時に取得することも可能である.

    三、対比

    public class ThreadTest {
        public static final String Lock = "lock";
        public final Object obj = new Object();
        synchronized void test1() throws InterruptedException {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("test1=" + i);
            }
        }
    
        synchronized static void test2() throws InterruptedException {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("test2=" + i);
            }
        }
    
        void test3() throws InterruptedException {
            synchronized (this) {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    System.out.println("test3=" + i);
                }
            }
        }
    
        void test4() throws InterruptedException {
            synchronized (this.getClass()) {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    System.out.println("test4=" + i);
                }
            }
        }
    
        void test5() throws InterruptedException {
            synchronized (Lock) {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    System.out.println("test5=" + i);
                }
            }
        }
    
        void test6() throws InterruptedException {
            synchronized (obj) {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    System.out.println("test6=" + i);
                }
            }
        }
    
        void test7() throws InterruptedException {
            synchronized (ThreadTest.Lock) {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    System.out.println("test7=" + i);
                }
            }
        }
    }

    一、同一オブジェクトの同一同期方法は同期である
    二、同じオブジェクトのsynchronizedメソッドとsynchronized(this)ブロックが同期メソッドtest 1とtest 3同期であるこの2つのメソッドのロックは、いずれも現在のオブジェクトに加算される
    三、クラスのstaticメソッドとsynchronized(このクラス)ブロックが同期のメソッドtest 2とtest 4が同期する両方のメソッドのロックはThreadTestクラスに加算され、メソッドtest 4のsynchronized(this.getClass()ブロックはsynchronized(ThreadTest.clss)に変換され、結果は同じですが、例えばsynchronized(String.class)に変換すると同期できません.ロックはクラスに加算されるので、したがって、同じクラスの2つの方法は同期されるだけでなく、同じクラスの異なるオブジェクト間の2つの方法も同期されます.
    四、第二点の二つの方法と第三点の二つの方法はtest 1とtest 2が同期せず、test 1とtest 4が同期せず、test 3とtest 2が同期せず、test 3とtest 4が同期しない
    五、synchronized(変数)は、ロックされたターゲットが異なるため、現在のクラスでも現在のオブジェクトでもないため、前の4つと同期しません.synchronized(obj)とsynchronized(this)の使い方はほぼ一致し、現在のオブジェクトにロックをかけます.synchronized(Lock)は現在のオブジェクトのほかに、本クラスの他の新しいオブジェクトも同期してロックされ、他のクラスでも呼び出されたsynchronized(ThreadTest.Lock)が同期します.
    六、ThreadTest 2のtest 7メソッドはThreadTestのtest 5メソッドと同期している.