JAVA高同時実行性(JUC)マルチスレッド8ロックの説明

最初に概念を理解します。同期ロックは、このメソッドが配置されているリソースクラス、つまりオブジェクトをロックします。つまり、2つのスレッドが同じ期間にこのリソースクラスに同時に入ることはできません。1つのスレッドのみが同じ期間にリソースクラスにアクセスできます。内部の同期メソッドの1つ!
T1:1。標準アクセス、最初にメールまたはテキストメッセージを印刷できますか?
コードは以下のように表示されます:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }
}

結果:sendEmailが最初に実行されますが、実際には必ずしも実行されません。cpuのスケジュールと同期による変更方法によっては、ロックされたオブジェクトがメソッドの呼び出し元になります。これら2つのメソッドは同じオブジェクトをロックするため、最初に呼び出されます。最初に実行されます。

T2:メール方式は4秒間停止されます。最初にメールまたはSMSを印刷できますか?
コードは以下のように表示されます:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }
}

結果:sendEmailが最初に実行され(4秒待機)、次にsendSMSが実行されますが、常に正しいとは限りません。これは、CPUのスケジュールと、同期による変更方法によって異なります。これら2つのメソッドはロックされているため、ロックされたオブジェクトはメソッドの呼び出し元です。これは同じオブジェクトであるため、最初の呼び出しが最初に実行されます。つまり、4秒後に、sendEmailが表示され、次にsendSMSが表示されます。これは、Wang Xiaopangが携帯電話を使用してメールを送信し、WangErpangが携帯電話を使用して短いメッセージを送信することを望んでいることと同じです。WangXiaopangは最初に電話を取得します。メールの送信には4秒かかるため、WangXiaopangがメールの送信を完了するまで4秒かかります。 、Wang Erfatはテキストメッセージを送信できます。
包括的なT1、T2:
結論:オブジェクトに複数の同期メソッドがある場合、特定の瞬間に、1つのスレッドが同期メソッドを呼び出す限り、他​​のスレッドは待機することしかできません。つまり、特定の時間しか存在できません。スレッドがこれらの同期されたメソッドにアクセスすると、現在のオブジェクトはロックされます。ロックされた後、他のオブジェクトは現在のオブジェクトの他の同期されたメソッドにアクセスできません。

T3:一般的なメソッドhello()を追加します。最初にメールを印刷してもいいですか、それともhelloですか?最初のhello
コードは次のとおりです。

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
//                phone.sendSMS();
                phone.hello();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");

    }
}

結果:helloは同期によって変更されないため、最初にhelloを出力し、4秒後にsendEmailを出力します。
結論:通常の方法は同期ロックとは何の関係もありません。

T4:2台の携帯電話、最初にメールやテキストメッセージを印刷できますか?
コードは以下のように表示されます:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
//                phone.sendSMS();
//                phone.hello();
                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

結果:リソースオブジェクトが異なるため、最初にphone1のsendSMSを印刷し、次に電話4sのsendmailを印刷します。
結論:2つのオブジェクトは同じロックではありません。

T5:同じ携帯電話の2つの静的同期方法で、最初に電子メールまたはテキストメッセージを印刷できますか?

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
//                phone.hello();
//                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public static synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

結果:最初にsendEmailを印刷し、4秒後にsendSMSを印刷します。

T6:前の質問で1台の携帯電話から2台の携帯電話に変更します。最初にメールやテキストメッセージを印刷できますか?
コードは以下のように表示されます:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
//                phone.sendSMS();
//                phone.hello();
                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public static synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

結果:最初にsendEmailを印刷し、4秒後にsendSMSを印刷します。
包括的なT5、T6:
結論:現時点では、ロックはオブジェクトではなく、クラスです。つまり、phone.classはロックされています。テンプレートがロックされ、Phone phone = new Phone()がこの電話をロックします。phoneとphone1はどちらもPhoneのインスタンスオブジェクトであり、ロックはPhoneであるため、電話の実行中は、ロックがテンプレートであるため、phone1は待機する必要があります。

T7:通常の同期方法1つ、静的同期方法1つ、携帯電話1つ、最初にメールやテキストメッセージを印刷できますか?
コードは以下のように表示されます:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
//        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
//                phone.hello();
//                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public  synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

結果:sendSMSが最初に印刷され、sendEmailが4秒後に印刷されました。理由:sendEmailはテンプレートをロックする(静的を追加する)ため、sendSMSはクラスをロックし、2つは競合しません。
T8:通常の同期方法1つ、静的同期方法1つ、携帯電話2つ、最初にメールやテキストメッセージを印刷できますか?
コードは以下のように表示されます:

public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "A").start();

        new Thread(() -> {
            try {
                phone1.sendSMS();
//                phone.hello();
//                phone1.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Phone {
    public static synchronized void sendEmail() throws Exception {
        Thread.sleep(4000);
        System.out.println("----sendEmail");
    }

    public  synchronized void sendSMS() throws Exception {
        System.out.println("----sendSMS");
    }

    public void hello() {
        System.out.println("----hello");
    }
}

結果:T7と同じで、sendSMSが最初に印刷され、sendEmailが4秒後に印刷されます。理由:sendEmailはテンプレートをロックする(静的を追加する)ため、sendSMSはテンプレートのインスタンスオブジェクトをロックし、異なるオブジェクトを操作します。2つは競合していません。

概要:
同期は同期の基礎を実現します:
javaのすべてのオブジェクトをロックとして使用できます。
次の3つの特定の症状があります
。1:通常のメソッドの場合、ロックは現在のインスタンスオブジェクトです。
2:静的同期メソッドの場合、ロックは現在のクラスのクラスオブジェクトです。
3:同期メソッドブロックの場合、ロックは同期ブラケットで構成されたオブジェクトです。
スレッドが同期されたコードブロックにアクセスしようとすると、最初にロックを取得し、終了または例外をスローしたときにロックを解放する必要があります。
つまり、インスタンスオブジェクトの非静的同期メソッドがロックを取得する場合、インスタンスオブジェクトの他の非静的同期メソッドは、ロックを取得する前に、ロックを取得するメソッドがロックを解放するのを待機する必要があります。別のインスタンスオブジェクトの非静的同期方法とインスタンスオブジェクトの非静的同期方法が異なるロックを使用する場合、インスタンスオブジェクトが取得したロックの非静的同期方法がロックを解放するのを待って、直接取得する必要はありません。ロック。
オブジェクトロックとクラスロック(this / class)は2つの異なるオブジェクトであるため、静的に同期されたメソッドと非静的に同期されたメソッドの間に競合条件はありません。ただし、静的メソッドがロックを取得すると、他の静的同期メソッドは、メソッドがロックを解放するのを待ってからロックを取得する必要があります。

おすすめ

転載: blog.csdn.net/Pzzzz_wwy/article/details/106040391