AtomicInteger et volatile
Je sais volatile
permet de visibilité, AtomicInteger
permet l'atomicité.
Donc, si j'utilise un volatile AtomicInteger
, ça veut dire je n'ai pas encore utiliser la synchronisation mécanismes?
Par exemple.
class A {
private volatile AtomicInteger count;
void someMethod(){
//do something
if(count.get() < 10) {
count.incrementAndGet();
}
}
Est ce thread-safe?
- Qu'entendez-vous par "thread-safe" ici? Il n'y a aucune garantie que le code ci-dessus signifie
count
ne va jamais au-dessus de 10, par exemple - plusieurs threads peuvent appelerintValue()
, et puis tous les appelsincrementAndGet()
. - Exactement, il en sera de ce travail? if(count.get() <10){ count.incrementAndGet(); } je crois que j'ai encore besoin d'une couche de synchronisation autour, n'est-ce pas?
- Je ne peux pas donner une réponse sur ce qui va "travailler" jusqu'à ce que vous donnez exigences. Il va compiler? Oui. Seront à éviter toutes les incréments de se perdre? Oui. Il va faire ce que vous voulez? Je ne peux pas dire.
- Je voulais dire "thread-safe"? Ce sens est-il sécuritaire de la perte de mises à jour?
- Oui, mais vous pourriez vous retrouver avec un nombre qui est plus grand que 10.
- Yep, bien comprise, il en aurait encore besoin d'une synchronisé bloc autour AtomicInteger. Merci beaucoup @JonSkeet
- Pas nécessairement. Cela dépend de vos besoins, que vous n'avez pas encore donné. À l'aide de
compareAndSet
dans une boucle, vous pouvez vous assurer que vous n'allez jamais au-dessus de 10. Mais je ne vais pas commencer à écrire un exemple de code pour vous aider à résoudre un problème que vous n'avez pas spécifié de façon suffisamment claire. - les conditions sont simples. Il doit être thread-safe, maintenant, que voulez-vous dire par là? À mon humble avis, depuis que je suis en train de faire un simple check-puis-loi, il "semble" que je ne veux pas de quelqu'un pour obtenir de count >10 et ce qui se passe dans un multi-thread env.("évidemment") . Merci pour toutes vos réponses, cependant.
- Non, rien de tout cela est évident. Il y a des situations où il pourrait être bien pour aller au-dessus d'une limite souple, mais pas bien de perdre le nombre de fois que vous avez dépassé cette limite. Compte tenu de vos besoins réels, je vous suggère de vous poser une nouvelle question à ces exigences, laissant celui-ci comme il est.
Vous devez vous connecter pour publier un commentaire.
Je crois que
Atomic*
, de fait, donne les deux l'atomicité et la volatilité. Ainsi, lorsque vous appelez le (dire)AtomicInteger.get()
, vous êtes garanti d'obtenir la dernière valeur. Ceci est documenté dans lejava.util.concurrent.atomic
la documentation du paquet:Maintenant, si vous avez
la
volatile
partie signifie que chaque thread va utiliser la dernièreAtomicInteger
de référence, et le fait que c'est unAtomicInteger
signifie que vous aurez aussi voir la dernière valeur de cet objet.Il n'est pas commun (IME) à besoin de cela - parce que, normalement, vous n'auriez pas réaffecter
count
pour faire référence à un autre objet. Au lieu de cela, vous auriez:À ce point, le fait que c'est un
final
variable signifie que tous les threads traitant du même objet - et le fait que c'est unAtomic*
objet signifie qu'ils vont voir la dernière valeur à l'intérieur de cet objet.intValue()
plutôt queget
?Je dirais que non, ce n'est pas thread-safe, si vous définissez "thread-safe" comme ayant le même résultat sous un seul mode arborescent et multithread mode. En mono-thread mode, le comte, ne sera jamais plus grand que 10, mais en mode multithread il peut.
Le problème est que
get
etincrementAndGet
est atomique, mais uneif
ne l'est pas. Gardez à l'esprit qu'un non-atomique opération peut être interrompue à tout moment. Par exemple:count = 9
actuellement.if(count.get() <10)
et obtienttrue
et s'est arrêtée là.if(count.get() <10)
et obtienttrue
trop pour qu'il fonctionnecount.incrementAndGet()
et de finitions. Maintenantcount = 10
.count.incrementAndGet()
, maintenantcount = 11
qui ne se produira jamais en single thread mode.Si vous voulez faire de ce "thread-safe" sans l'aide de
synchronized
qui est plus lent, essayez cette mise en place:Réponse est là, dans ce code,
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java
C'est le code source de AtomicInteger.
La valeur est Volatile.
Donc,AtomicInteger utilise Volatile à l'intérieur.
De conserver l'original de la sémantique, et le soutien de plusieurs threads, vous pourriez faire quelque chose comme:
Cela évite de n'importe quel thread jamais voir le comte atteindre 10.