Si j'ai 2 méthodes synchronisées dans la même classe, mais chacune accédant à des variables différentes, est-ce que 2 threads peuvent accéder à ces 2 méthodes en même temps? Le verrou se produit-il sur l'objet ou est-il aussi spécifique que les variables à l'intérieur de la méthode synchronisée?
Exemple:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
Deux threads peuvent-ils accéder à la même instance de classe X exécutant x.addA(
) et x.addB()
en même temps?
synchronized (this)
bloc autour du corps de la méthode. L'objet «this» ne se verrouille pas, mais l'objet «this» est utilisé comme mutex et le corps est empêché de s'exécuter simultanément avec d'autres sections de code également synchronisées sur «this». Cela n'a aucun effet sur les autres champs / méthodes de "this" qui ne sont pas synchronisés.a
etb
étaient des objets, par exempleInteger
s, vous synchronisiez sur des instances que vous remplacez par des objets différents lors de l'application de l'++
opérateur.Synchronisé sur la déclaration de méthode, le sucre syntaxique est pour cela:
Sur une méthode statique, c'est du sucre syntaxique pour cela:
Je pense que si les concepteurs Java savaient alors ce que l'on comprend maintenant sur la synchronisation, ils n'auraient pas ajouté le sucre syntaxique, car cela conduit le plus souvent à de mauvaises implémentations de concurrence.
la source
À partir de "Les didacticiels Java ™" sur les méthodes synchronisées :
Depuis «Les didacticiels Java ™» sur les blocs synchronisés :
(Je souligne le mien)
Supposons que vous ayez 2 variables non entrelacées . Vous voulez donc accéder à chacun à partir d'un thread différent en même temps. Vous devez définir le verrou non pas sur la classe d'objet elle-même, mais sur la classe Object comme ci-dessous (exemple du deuxième lien Oracle):
la source
Le verrou auquel on accède est sur l'objet, pas sur la méthode. Les variables auxquelles on accède dans la méthode ne sont pas pertinentes.
L'ajout de «synchronisé» à la méthode signifie que le thread exécutant le code doit acquérir le verrou sur l'objet avant de continuer. L'ajout de "statique synchronisé" signifie que le thread exécutant le code doit acquérir le verrou sur l'objet de classe avant de continuer. Vous pouvez également envelopper le code dans un bloc comme celui-ci:
afin que vous puissiez spécifier l'objet dont le verrou doit être acquis.
Si vous souhaitez éviter de verrouiller l'objet contenant, vous pouvez choisir entre:
la source
À partir de la documentation d'Oracle lien de
La synchronisation des méthodes a deux effets:
Consultez cette page de documentation pour comprendre les verrous intrinsèques et le comportement des verrous.
Cela répondra à votre question: sur le même objet x, vous ne pouvez pas appeler x.addA () et x.addB () en même temps lorsqu'une des méthodes synchronisées est en cours d'exécution.
la source
Si vous avez des méthodes qui ne sont pas synchronisées et qui accèdent et modifient les variables d'instance. Dans votre exemple:
n'importe quel nombre de threads peut accéder à ces méthodes non synchronisées en même temps lorsqu'un autre thread est dans la méthode synchronisée du même objet et peut apporter des modifications aux variables d'instance. Par exemple: -
Vous devez éviter le scénario selon lequel des méthodes non synchronisées accèdent aux variables d'instance et les modifient, sinon il est inutile d'utiliser des méthodes synchronisées.
Dans le scénario ci-dessous: -
Un seul des threads peut être dans la méthode addA ou addB, mais en même temps, n'importe quel nombre de threads peut entrer la méthode changeState. Deux threads ne peuvent pas entrer addA et addB en même temps (en raison du verrouillage au niveau de l'objet) mais en même temps n'importe quel nombre de threads peuvent entrer changeState.
la source
Vous pouvez faire quelque chose comme ce qui suit. Dans ce cas, vous utilisez le verrou sur a et b pour synchroniser au lieu du verrou sur «ceci». Nous ne pouvons pas utiliser int car les valeurs primitives n'ont pas de verrous, nous utilisons donc Integer.
la source
Oui, cela bloquera l'autre méthode car la méthode synchronisée s'applique à l' objet de classe TOUT comme pointé .... mais de toute façon, elle bloquera l'exécution de l'autre thread UNIQUEMENT lors de l'exécution de la somme dans n'importe quelle méthode addA ou addB qu'elle entre, car quand elle se termine ... l'un des threads libérera l'objet et l'autre thread accédera à l'autre méthode et ainsi de suite fonctionnera parfaitement.
Je veux dire que le "synchronisé" est fait précisément pour empêcher l'autre thread d'accéder à un autre pendant l'exécution d'un code spécifique. Donc, finalement, ce code fonctionnera très bien.
En guise de note finale, s'il y a des variables 'a' et 'b', pas seulement une variable unique 'a' ou tout autre nom, il n'est pas nécessaire de synchroniser ces méthodes car il est parfaitement sûr d'accéder à d'autres var (Other memory emplacement).
Fonctionnera aussi
la source
Cet exemple (bien que pas joli) peut fournir plus d'informations sur le mécanisme de verrouillage. Si incrementA est synchronisé , et incrementB n'est pas synchronisé , alors incrementB sera exécuté dès que possible, mais si incrementB est également synchronisé, alors il doit `` attendre '' que incrementA se termine, avant qu'incrementB puisse faire son travail.
Les deux méthodes sont appelées sur une seule instance - objet, dans cet exemple, il s'agit de: job , et les threads «concurrents» sont un thread et main .
Essayez avec ' synchronized ' dans incrementB et sans cela et vous verrez des résultats différents.Si incrementB est également ' synchronized ', alors il doit attendre que incrementA () se termine. Exécutez plusieurs fois chaque variante.
la source
Dans la synchronisation java, si un thread veut entrer dans la méthode de synchronisation, il acquiert le verrouillage sur toutes les méthodes synchronisées de cet objet et pas seulement sur une méthode synchronisée que le thread utilise. Ainsi, un thread exécutant addA () acquiert un verrou sur addA () et addB () car les deux sont synchronisés, donc les autres threads avec le même objet ne peuvent pas exécuter addB ().
la source
Cela peut ne pas fonctionner car le boxing et l'autoboxing de Integer vers int et vice versa dépendent de JVM et il est fort possible que deux nombres différents soient hachés à la même adresse s'ils sont compris entre -128 et 127.
la source