Ai-je besoin de synchroniser des méthodes à l'intérieur de la méthode d'exécution en Java lors de l'appel méthode de démarrage?

StackOverflow https://stackoverflow.com/questions/8351825

Question

Quelqu'un peut-il me dire si je suis bien ou pas? J'ai deux fils qui se déroulera en parallèle.

class MyThread extends Thread {

    MyThread() {
    }

    method1() {
    }

    method2() {
    }

    method3() {
    }

    approach(1):

        run() {
            method1();
            method2();
            method3();
        }

    approach(2):

        run() {
            //the code of method1 is here (no method calling)
            //the code of method2 is here (no method calling)
            //the code of method3 is here (no method calling)
        }

}

class Test{
    public static void main(){
        Thread t1 = new Thread();
        t1.start();
        Thread t2 = new Thread();
        t2.start();
    }
}

method1, method2 et method3 font des données partagées globales non accès mais leurs codes exercent une partie écriture dans la variable locale dans la section de la méthode, je suppose donc je ne peux pas permettre l'exécution de chevauchement dans la section de la méthode.

De ce fait: en approach(1): Je dois faire les méthodes (method1, method2 et method3) synchronisées, droit

?

approach(2): Pas besoin de synchroniser les sections de code, droit

Si je ne me trompe pas dans les deux approche, en utilisant la approach(2) donnera de meilleures performances, droit?

Était-ce utile?

La solution

Vous dites vos méthodes n'accèdent pas de données globales partagées et écrire uniquement des variables locales donc il n'y a pas besoin de les synchroniser Parce que les deux fils seront ayant leurs propres copies des variables locales. Ils ne se chevauchent pas ou quelque chose.

Ce genre de problème est confronté en cas de variables statiques / classe. Si plusieurs threads tentent de modifier la valeur des variables statiques en même temps alors il vient le problème donc il nous faut synchroniser.

Autres conseils

Réponse courte: vous n'avez pas besoin de la synchronisation. Les deux approches sont équivalentes du point de vue de la sécurité des threads.

Deuxième réponse:

Il peut être intéressant de jeter un pas en arrière et se rappeler ce que le bloc synchronisé fait. Il fait essentiellement deux choses:

  1. fait en sorte que si le thread A est à l'intérieur d'un bloc qui est synchronisé sur M objet, aucun autre thread ne peut entrer dans un bloc qui est synchronisé sur le même objet M jusqu'à ce que le thread A est fait avec son bloc de code
  2. fait en sorte que si le thread A fait exécuter le travail dans un bloc qui est synchronisé objet M, puis se termine ce bloc, puis le fil B entre dans un bloc qui est également synchronisé sur M, puis enfilez B voir tout ce que le thread A avait fait dans son bloc synchronisé. On appelle cela l'établit arrive-avant relation.

Notez qu'une méthode synchronisée est un raccourci juste pour envelopper le code de la méthode synchronisée (ce) {...}.

En plus de ces deux choses, le modèle mémoire de Java (JMM) garantit que, dans un fil, les choses vont se passer comme si elles avaient pas été réorganisés. (Ils peuvent effectivement être réorganisés pour diverses raisons, y compris l'efficacité - mais pas d'une manière que votre programme peut remarquer dans un seul thread Par exemple, si vous le faites. « X = 1, y = 2 » le compilateur est libre de commutateur que tel que y = 2 se produit avant que x = 1, car un seul thread peut ne pas remarquer en fait la différence. Si plusieurs threads accèdent x et y, alors il est très possible, sans une bonne synchronisation, pour un autre thread pour voir y = 2 avant qu'il ne voit x = 1).

Alors, pour revenir à votre question initiale, il y a quelques notes intéressantes.

D'abord, puisqu'une méthode synchronisée est un raccourci pour mettre la méthode tout dans un « synchronisé (this) {...} » bloc, les méthodes et les méthodes de t2 de t1 ne seront pas synchronisées contre la même référence, et ne sera donc pas synchronisée par rapport à l'autre. Les méthodes de t1 ne seront synchronisées contre l'objet t1, t2 et ce ne seront synchronisées contre t2. En d'autres termes, il serait parfaitement bien pour t1.method1 () et t2.method1 () pour exécuter en même temps. Alors, ces deux choses le mot-clé synchronisé fournit, le premier (l'exclusivité d'entrer dans le bloc) n'est pas pertinent. Les choses pourraient aller quelque chose comme:

  1. t1 veut entrer method1. Il a besoin d'acquérir le moniteur t1, qui ne prétend pas - il l'acquiert et pénètre dans le bloc
  2. t2
  3. . veut entrer method2. Il a besoin d'acquérir le 11 moniteur, qui ne prétend pas - est qu'elle acquiert et pénètre dans le bloc
  4. se termine t1 MÉTHODE1 et libère son emprise sur le moniteur t1
  5. finitions t2 MÉTHODE1 et libère son emprise sur le moniteur t2

En ce qui concerne la deuxième synchronisation de chose ne (établir arrive-avant), ce qui rend method1 () et method2 () synchronisée sera essentiellement veiller à ce que t1.method1 () a lieu avant-t1.method2 (). Mais puisque les deux personnes se produisent sur le même fil de toute façon (le fil t1), les garanties de toute façon de JMM que cela se produira.

Il se fait même un peu plus laid. Si t1 et t2 fait état d'actions - qui est, la synchronisation serait nécessaire - alors faire les méthodes synchronized serait pas suffisant. Rappelez-vous, un moyen de méthode synchronisée synchronized (this) {...}, si les méthodes de t1 seraient synchronisées contre t1, t2 et ce serait contre t2. Vous en fait pas établirez tout se passe-avant relation entre les méthodes de t1 et t2 de.

, vous auriez plutôt de faire en sorte que les méthodes sont synchronisées sur la même référence . Il existe différentes façons de le faire, mais au fond, il doit être une référence à un objet que les deux fils les deux connaissent.

On suppose t1 et t2 savons tous les deux de la même référence, LOCK. Tous les deux ont des méthodes telles que:

method1() {
    synchronized(LOCK) {
        // do whatever
    }
}

Maintenant, les choses pourraient aller quelque chose comme ça:

  1. t1 veut entrer method1. Il a besoin d'acquérir le moniteur LOCK, qui ne prétend pas - il l'acquiert et pénètre dans le bloc
  2. t2 veut entrer method1. Il a besoin d'acquérir le moniteur LOCK, qui est déjà détenu par t1 -. Donc t2 est mis en attente
  3. se termine t1 MÉTHODE1 et libère son emprise sur l'écran LOCK
  4. t2 est maintenant en mesure d'acquérir le moniteur LOCK, il le fait, et commence sur la viande de method1
  5. finitions t2 MÉTHODE1 et libère son emprise sur l'écran LOCK

Si les méthodes que vous appelez ne pas écrire les données globales partagées, vous n'avez pas de les synchroniser.

Dans un programme multithread, chaque thread a sa propre pile d'appel. Les variables locales de chaque méthode seront séparés dans chaque fil, et ne va pas écraser les uns des autres.

Par conséquent, l'approche 1 fonctionne très bien, ne nécessite pas les frais généraux de synchronisation, et est bien meilleure pratique de la programmation car elle évite le code dupliquée.

Discussion-sage votre ok. des variables locales dans les méthodes ne sont pas partagées entre les threads que chaque instance en cours d'exécution dans un thread aura sa propre pile.

Vous n'avez des améliorations de la vitesse entre les deux approches, il est juste une meilleure organisation du code (méthodes plus courtes sont plus faciles à comprendre)

Si chaque méthode est indépendante de l'autre, vous pouvez envisager si elles appartiennent à la même classe. Si vous voulez que le gain de performance créer 3 classes différentes et exécuter plusieurs threads pour chaque méthode (gains de performance dépend du nombre de rations cpu noyaux disponibles / io etc.)

Ainsi: approche (1): Je dois faire les méthodes (method1, method2 et MÉTHODE3) synchronisé, non? dans l'approche (2): Non à besoin synchroniser les sections de code, droit?

méthodes Invoking alignés en V / S invoquant plusieurs méthodes ne déterminent pas si une méthode doit être synchronisé ou non. Je vous recommande de lire puis demander plus clarifications.

Si je ne me trompe pas dans les deux approche, en utilisant l'approche (2) donnera de meilleures performances, droit?

Au prix de décomposer les méthodes en une seule méthode de Dieu? Bien sûr, mais vous regarderez un « très » amélioration miniscule par rapport à la lisibilité du code perdu, quelque chose certainement pas recommandé.

method1, 2 et 3 ne sera pas exécutée simultanément si les variables qu'ils en lecture / écriture ne sont pas partagées en dehors de la classe avec d'autres threads pendant leur exécution alors il n'y a pas de synchronisation nécessaire et pas besoin de ligne.

Si elles modifient les données que les autres threads lus en même temps qu'ils courent, alors vous devez garder l'accès à ces données.

Si elles lisent les données que les autres threads écrire en même temps qu'ils courent alors vous devez garder l'accès à ces données.

Si d'autres threads devraient lire les données modifiées par method1, 2 ou 3, vous devez faire synchroniser la méthode d'exécution (ou les dans un bloc synchronisé) pour mettre en place une porte de telle sorte que la machine virtuelle Java sera mis en place un barrière mémoire et veiller à ce que d'autres fils peuvent voir les données après M1,2 et 3 sont effectuées.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top