Explication de 8 verrous multi-threads JAVA à haute concurrence (JUC)

Comprenez d'abord un concept: synchronized verrouille la classe de ressources où se trouve cette méthode, c'est-à-dire l'objet, c'est-à-dire qu'il est impossible pour deux threads d'entrer dans cette classe de ressources en même temps pendant la même période. Un seul thread est autorisé à accéder à la classe de ressources à la même période. Une des méthodes synchronisées à l'intérieur!
T1: 1. Accès standard, puis-je d'abord imprimer des e-mails ou des SMS?
code montrer comme ci-dessous:

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");
    }
}

Résultat: bien que sendEmail soit exécuté en premier, ce n'est pas nécessairement le cas. En fonction de la planification du processeur et de la manière dont il est modifié par synchronisé, l'objet verrouillé est l'appelant de la méthode. Ces deux méthodes verrouillant le même objet, elles sont appelées en premier Exécuté en premier.

T2: La méthode de courrier électronique est suspendue pendant 4. Puis-je imprimer le courrier électronique ou le SMS en premier?
code montrer comme ci-dessous:

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");
    }
}

Résultat: bien que sendEmail soit exécuté en premier (en attente de 4 s), puis que sendSMS soit suivi, ce n'est pas toujours vrai. Cela dépend de la planification du processeur et de la façon dont il est modifié par synchronisation. L'objet verrouillé est l'appelant de la méthode, car ces deux méthodes sont verrouillées C'est le même objet, donc le premier appel est exécuté en premier, c'est-à-dire qu'après 4s, sendEmail apparaît, puis sendSMS. Cela équivaut à ce que Wang Xiaopang veut utiliser le téléphone portable pour envoyer des e-mails, et Wang Erpang veut utiliser le téléphone portable pour envoyer des messages courts. Wang Xiaopang prend le téléphone en premier. Il faut 4 secondes pour envoyer des e-mails, il faut donc 4 secondes pour attendre que Wang Xiaopang finisse d'envoyer des e-mails , Wang Er fat peut envoyer des messages texte.
T1, T2 complet:
Conclusion: S'il y a plusieurs méthodes synchronisées dans un objet, à un certain moment, tant qu'un thread appelle la méthode synchronisée, alors les autres threads ne peuvent qu'attendre. En d'autres termes, il ne peut y avoir qu'un certain temps Lorsqu'un thread accède à ces méthodes synchronisées, l'objet courant est verrouillé. Après avoir été verrouillé, aucun autre objet ne peut accéder aux autres méthodes synchronisées de l'objet courant.

T3: Ajouter une méthode courante bonjour (), puis-je imprimer le courrier électronique en premier ou bonjour? Le premier
code bonjour est le suivant:

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");

    }
}

Résultat: le résultat est d'imprimer d'abord bonjour, puis de sendEmail 4s plus tard, car bonjour n'est pas modifié par synchronisé.
Conclusion: la méthode normale n'a rien à voir avec les verrous de synchronisation.

T4: Deux téléphones portables, puis-je d'abord imprimer des e-mails ou des SMS?
code montrer comme ci-dessous:

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");
    }
}

Résultat: imprimez d'abord sendSMS de phone1, puis imprimez sendmail de phone 4s plus tard, car les objets de ressource sont différents.
Conclusion: deux objets ne sont pas le même verrou.

T5: Deux méthodes de synchronisation statiques, le même téléphone portable, puis-je d'abord imprimer des e-mails ou des SMS?

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");
    }
}

Résultat: imprimez d'abord sendEmail, puis sendSMS après 4s.

T6: Passer d'un téléphone portable à deux téléphones portables à la question précédente Puis-je imprimer des e-mails ou des SMS en premier?
code montrer comme ci-dessous:

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");
    }
}

Résultat: imprimez d'abord sendEmail, puis sendSMS après 4s.
T5 complet, T6:
Conclusion: à ce moment, le verrou n'est pas l'objet, mais la classe! Autrement dit, phone.class est verrouillé! Le modèle est verrouillé et Phone phone = new Phone () verrouille ce téléphone. Étant donné que phone et phone1 sont tous deux des objets d'instance de Phone et que le verrou est Phone, lorsque le téléphone est en cours d'exécution, phone1 doit attendre, car le verrou est le modèle.

T7: 1 méthode de synchronisation normale, 1 méthode de synchronisation statique, 1 téléphone portable, puis-je imprimer des e-mails ou des messages texte en premier?
code montrer comme ci-dessous:

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");
    }
}

Résultat: sendSMS imprimé en premier, puis sendEmail imprimé 4 s plus tard. Raison: étant donné que sendEmail verrouille le modèle (ajoutez de la statique), sendSMS verrouille la classe et les deux ne sont pas en conflit.
T8: 1 méthode de synchronisation normale, 1 méthode de synchronisation statique, 2 téléphones portables, puis-je imprimer des e-mails ou des messages texte en premier?
code montrer comme ci-dessous:

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");
    }
}

Résultat: identique à T7, sendSMS imprimé en premier, puis sendEmail imprimé 4s plus tard. Raison: étant donné que sendEmail verrouille le modèle (ajout de la valeur statique), sendSMS verrouille l'objet d'instance du modèle et fonctionne sur différents objets. Les deux ne sont pas en conflit.

Résumé: La
synchronisation réalise la base de la synchronisation:
chaque objet en java peut être utilisé comme verrou.
Il existe trois manifestations spécifiques comme suit:
1: Pour les méthodes ordinaires, le verrou est l'objet d'instance actuel.
2: Pour les méthodes de synchronisation statique, le verrou est l'objet de classe de la classe actuelle.
3: Pour le bloc de méthode synchronisée, le verrou est l'objet configuré entre crochets synchronisés.
Lorsqu'un thread tente d'accéder à un bloc de code synchronisé, il doit d'abord obtenir le verrou et doit libérer le verrou lorsqu'il quitte ou lève une exception.
Autrement dit, lorsqu'une méthode de synchronisation non statique d'un objet d'instance acquiert un verrou, d'autres méthodes de synchronisation non statiques de l'objet d'instance doivent attendre que la méthode d'acquisition du verrou libère le verrou avant d'acquérir le verrou. Si la méthode de synchronisation non statique d'un autre objet d'instance et la méthode de synchronisation non statique de l'objet d'instance utilisent des verrous différents, il n'est pas nécessaire d'attendre la méthode de synchronisation non statique du verrou que l'objet d'instance a acquis pour libérer le verrou et s'acquitter directement d'eux-mêmes. Fermer à clé.
Le verrouillage d'objet et le verrouillage de classe (this / class) sont deux objets différents, il n'y aura donc pas de conditions de concurrence entre les méthodes synchronisées statiquement et les méthodes synchronisées non statiques. Mais une fois que la méthode statique acquiert le verrou, les autres méthodes de synchronisation statiques doivent attendre que la méthode libère le verrou avant d'acquérir le verrou.

Je suppose que tu aimes

Origine blog.csdn.net/Pzzzz_wwy/article/details/106040391
conseillé
Classement