Javaの同じクラスで異なるsynchronizedメソッドを同時に実行できますか?

5069 ワード

「Javaの2つのスレッドは、1つのオブジェクトに質問できるかどうかの2つの異なるsynchronizedメソッドと同じですか??」
答えは:いけません!!!
この問題はあなたから見れば明らかかもしれませんが、私はずっと考えています.
いくつかの異なるスレッドがクラスの同じsynchronizedメソッドに同時にアクセスすると、1つのスレッドが実行されると、他のスレッドが待機します.複数の異なるスレッドが1つのクラスの異なるsynchronizedにアクセスする場合、同時に実行することができる.
大神さん達に笑われました~~
=========しかし、もしあなたも私と同じ観念があれば、下の文字をよく読んでください!!
複数のスレッドが同じクラスのsynchronizedメソッドにアクセスする場合、シリアルで実行されます!複数のcpuがあっても例外ではありません!synchronizedメソッドはクラスjavaの内蔵ロックを用いる、すなわちメソッドが属するオブジェクト自体をロックする.同じロックのある時点は1つの実行スレッドによってしか取得できないため、他のスレッドはロックの解放を待たなければならない.そのため、余分なcpuが実行できるとしても、ロックがないのでsynchronizedメソッドの実行に入ることができず、CPUが空いています.あるスレッドが長い間競争の激しいロックを持っていると、他のスレッドが待機解放によって停止するため、CPUが利用できなくなり、システムのスループットが低下する.そのため、あるスレッドのロックに対する長期的な占有をできるだけ避けなければなりません.
以下に検証コードを示します.
public class SyncMethod {

    public synchronized void syncMethod2() {
        try {
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)");
    }

    public synchronized void syncMethod1() {
        System.out.println("######################## (syncMethod1,        `SyncMethod.this`,      )");
    }


    static class Thread1 extends Thread {
        SyncMethod syncMethod;

        public Thread1(SyncMethod syncMethod) {
            this.syncMethod = syncMethod;
        }

        @Override
        public void run() {
            syncMethod.syncMethod2();
        }
    }

    static class Thread2 extends Thread {
        SyncMethod syncMethod;

        public Thread2(SyncMethod syncMethod) {
            this.syncMethod = syncMethod;
        }

        @Override
        public void run() {
            System.out.println("Thread2 running ...");
            syncMethod.syncMethod1();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncMethod syncMethod = new SyncMethod();
        Thread1 thread1 = new Thread1(syncMethod);
        Thread2 thread2 = new Thread2(syncMethod);

        thread1.start();    //   ,      
        Thread.sleep(500); //  cpu,  thread1  ,      

        thread2.start(); // syncMethod1()      ,   syncMethod2()      

        /*
                      synchronized  ,              synchronized   

        1.        synchronized     `syncMethod`
        2.        (Thread1),      syncMethod   sychronized  (syncMethod1) ,      synchronized   
        3.        (Thread2),    syncMethod     synchronized  (syncMethod2),           

            : 
        @@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)
        Thread2 running ...
        @@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)
        ######################## (syncMethod1,        `SyncMethod.this`,      )

            : 
                ,    `Thread2 running ...`      (Thread2         ,       Thread1  ).

                               synchronized    , 
                cpu    (Thread1   syncMethod1   Thread.sleep   cpu), 
            Thread2   syncMethod2        ,    syncMethod2       `Thread2 running ...`         , 
                       (           Thread2  cpu,             cpu), 
                  : "                 synchronized  "

                       ,         ,       .
        */

    }
}

ロックの使用に関するいくつかの提案は、ロックの競合を回避するために、ロックの分解、ロックセグメント化、スレッドのロックの保持時間を短縮することができます.控訴プログラムのsyncMethod 1とsyncMethod 2の方法が2つの関連のない方法(要求されたリソースには関係がありません)である場合、この2つの方法はそれぞれ2つの異なるロックを使用することができます.改造後のSyncMethod類は以下の通りである.
public class SyncMethod {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void syncMethod2() {
        synchronized (lock1) {
            try {
                System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)");
        }
    }

    public void syncMethod1() {
        synchronized (lock2) {
            System.out.println("######################## (syncMethod1,        `SyncMethod.this`,      )");
        }
    }
}

改造後のThread 1とThread 2は発生せず、ロック競合によりハングアップする場合がある.
もちろん、syncMethod 1における消費時間操作がロックリソースとは無関係である場合には、消費時間操作を同期ブロックから取り出すようにしてもよい.上記の改造に基づくsyncMethod 1の更なる改造は以下の通りである.
public void syncMethod2() {
    synchronized (lock1) {
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)");
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2,        `SyncMethod.this`)");
    }


    //          
    try {
        Thread.sleep(5000);//               
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}