Quels sont les Cas qui Nécessitent Méthode Synchronisée Accès en Java?
Dans quels cas est-il nécessaire de synchroniser l'accès pour les membres de l'instance?
Je comprends que l'accès aux membres statiques d'une classe doit toujours être synchronisé - parce qu'elles sont partagées par tous les objets instances de la classe.
Ma question est: quand dois-je être incorrect si je n'ai pas synchroniser les membres de l'instance?
par exemple si ma classe est
public class MyClass {
private int instanceVar = 0;
public setInstanceVar()
{
instanceVar++;
}
public getInstanceVar()
{
return instanceVar;
}
}
dans ce cas (de l'utilisation de la classe MyClass
) aurais-je besoin de disposer de méthodes pour:
public synchronized setInstanceVar()
et
public synchronized getInstanceVar()
?
Merci d'avance pour vos réponses.
Vous devez vous connecter pour publier un commentaire.
Cela dépend si vous voulez que votre classe thread-safe. La plupart des classes ne doit pas être thread-safe (pour des raisons de simplicité) dans ce cas, vous n'avez pas besoin de synchronisation. Si vous en avez besoin pour être thread-safe, vous devez synchroniser l'accès ou faire de la variable volatile. (Il évite les autres threads obtention de données "obsolètes.)
La
synchronized
modificateur est vraiment un mauvais idée et devrait être évitée à tous les frais. Je pense qu'il est louable que le Soleil a essayé de faire de verrouiller un peu plus facile à réaliser, maissynchronized
des causes justes, plus d'ennuis que cela vaut la peine.Le problème est qu'un
synchronized
méthode est en fait juste la syntaxe de sucre pour obtenir un verrou surthis
et la détention pour la durée de la méthode. Ainsi,public synchronized void setInstanceVar()
serait équivalent à quelque chose comme ceci:C'est mauvais pour deux raisons:
synchronized
méthodes au sein de la même classe d'utiliser exactement la même serrure, ce qui réduit le débitIl n'y a rien pour m'empêcher de faire quelque chose comme cela dans une autre classe:
À l'intérieur de cette
synchronized
bloc, je suis maintenant le verrou qui est requis par tous lessynchronized
méthodes au sein deMyClass
. Cela réduit d'autant le débit et considérablement augmente les chances d'une impasse.Une meilleure approche est d'avoir un dédié
lock
objet et utiliser lesynchronized(...)
bloc directement:Alternativement, vous pouvez utiliser le
java.util.concurrent.Lock
de l'interface et lajava.util.concurrent.locks.ReentrantLock
mise en œuvre pour obtenir essentiellement le même résultat (en fait, c'est la même chose sur la version 6 de Java).private static final Object lock = new Object(); // must be static final
lock
êtrestatic
puisque les données qu'il est en cours de synchronisation (instanceVar
) lui, n'est pas statique. Statique serrures sont presque toujours un signe de très, de très graves problèmes, et il faut éviter autant que possible.Thread
est vraiment juste un détail d'implémentation. C'est une mauvaise pratique, btw, mais reste faisable. Si vous le faites, alors vous aurez au moins deux threads s'exécutant sur la même instance. Ces fils à utiliser le même verrou de l'objet. Toutefois, pour les threads en cours d'exécution contre les différentes instances deMyClass
, il n'y a pas de point de blocage sur le même objet, car ils ne sont pas accès aux mêmes informations! Donc, nous pourrions la rendre statique, mais il n'y a absolument aucun avantage et beaucoup de douleur, si nous le faisons.private static final Object = new Object()
. Cependant, si la méthode qui met à jour le champ statique est lui-même statique, nous pouvons atteindre la même synchronisation par le simple fait de déclarer la méthode synchronized.lock
aurait besoin d'être statique et l'utilisation de lasynchronized
modificateur serait acceptable (mais toujours pas de préférence).Si vous voulez faire de cette classe thread-safe, je voudrais déclarer
instanceVar
commevolatile
de faire en sorte que vous obtenez toujours le plus à jour la valeur de la mémoire et aussi je voudrais faire lesetInstanceVar()
synchronized
parce que dans la JVM d'un incrément n'est pas une opération atomique.. En gros, la réponse est "ça dépend". La synchronisation de votre setter et getter ici serait seulement le but de garantir que plusieurs threads ne pouvait pas lire les variables entre les uns et les autres opérations d'incrémentation:
mais qui ne serait pas vraiment à même de travailler ici, parce que pour s'assurer que votre thread appelant a obtenu la même valeur incrémentée, vous avez la garantie que vous êtes atomiquement incrémentation et de l'extraction puis, que vous n'êtes pas ici - je.e que vous avez à faire quelque chose comme
Fondamentalement, la synchronisation est utile pour définir les opérations qui doivent être garantis à l'exécution des threads (inotherwords, vous ne pouvez pas créer une situation où un thread séparé de sape de votre opération et votre classe de comportement illogique, ou portant atteinte à ce qui vous attend de l'état des données). C'est effectivement une question importante que ce qui peut être abordé ici.
Ce livre Java de la Simultanéité dans la Pratique est excellent, et certainement beaucoup plus fiable que moi.
Pour le dire simplement, vous utilisez synchronisés lorsque vous avez plusieurs threads accèdent à la même méthode de la même instance qui va changer l'état de l'objet/ou de l'application.
C'est un moyen simple d'éviter les conditions de concurrence entre les threads, et vraiment, vous devez utiliser uniquement lorsque vous prévoyez d'avoir simultanées threads accèdent à la même instance, comme un objet global.
Maintenant, quand vous la lecture de l'état d'une instance d'un objet avec des threads simultanés, vous voudrez peut-être chercher dans le java.util.de façon concomitante.les verrous.ReentrantReadWriteLock -- qui, en théorie, permet à plusieurs threads de lire à un moment, mais un seul thread est autorisé à écrire. Ainsi, dans la lecture et de réglage de la méthode de l'exemple que tout le monde semble être de donner, vous pouvez effectuer les opérations suivantes:
En Java, les opérations sur les entiers sont atomiques donc pas, dans ce cas, vous n'avez pas besoin de synchroniser si tout ce que vous faites est de 1 à écrire et à 1 lire à la fois.
Si ceux-ci étaient longs ou double, vous avez besoin de synchroniser car il est possible pour une partie de la long double, pour être mis à jour, puis un autre thread de lecture, puis enfin l'autre partie de la longue/double mise à jour.