8
votes

Comment écrire une classe de fil-sécurité simple à l'aide d'une variable volatile?

Je veux écrire un simple la classe de sécurité em> qui pourrait être utilisée pour définir ou obtenir une valeur entière.

Le moyen le plus simple consiste à utiliser le synchronisé fort> Mot clé: P>

public class MyIntegerHolder {

    private AtomicInteger atomicInteger = new AtomicInteger();

    public Integer getValue() {
        return atomicInteger.get();
    }

    public void setValue(Integer value) {
        atomicInteger.set(value);
    }

}


3 commentaires

J'apprends toujours, si quelqu'un pouvait me clarifier une chose, ce serait génial. Comment le synchronisé ou volatile Les mots-clés le rendent plus Safe Safe ? Depuis que l'affectation entière et la lecture sont atomiques par elles-mêmes, cela change-t-il quelque chose? Cette approche n'autorise ni les augmentations atomiques ni se mettre de toute façon. Merci


@Sebi Thread-Safe est un programme qui fonctionne dans deux fils ou plus, sans fil interférant sur un autre. Vous pouvez résoudre ce problème, un fil interférant dans un autre, de différentes manières / techniques. Un SIMPLET INT X = X + X semble être atomique, mais n'est pas (plus pour cela, recherchez volatile et atomique)! Pour "rendre plus sûr du fil de fil", n'est qu'un moyen de résoudre le problème. Cela ne fait pas plus de thread-coffre-fort, est juste une implémentation différente pour résoudre le même problème.


@Thufirhawat Je suis conscient de ce qui est un programme de sécurité à fil ou que l'addition implique plusieurs lectures avant l'écriture, mais je suis sûr qu'il y a quelque chose que je n'ai pas sur cette classe. Je ne sais pas la saisie de la manière dont une classe exposant un getter et un réglage pour un entier pourrait être utilisée pour faire quoi que ce soit exigeant la sécurité du fil sans être verrouillé à l'extérieur (où entier suffirait).


5 Réponses :


1
votes

Si vous n'avez besoin que d'obtenir / définir une variable, il suffit de le déclarer volatil comme vous l'avez fait. Si vous vérifiez comment AtomicInteger Set / Obtenir le travail, vous verrez la même implémentation

private volatile int value;
...

public final int get() {
    return value;
}

public final void set(int newValue) {
    value = newValue;
}


0 commentaires

4
votes

Le mot clé synchronisé code> dit que si filetage A et thread b code> veulent accéder au integer code>, ils ne peuvent pas le faire simultanément. A dit b'attendez que j'avais fini avec elle.

d'autre part, volatile code> fait des fils plus "sympathiques". Ils commencent à se parler et à travailler ensemble pour effectuer des tâches. Donc, quand B tente d'accéder, une volonté informera B de tout ce qu'elle a fait jusqu'à ce moment-là. B est maintenant conscient des changements et peut poursuivre son travail d'où une gauche de. P>

en Java, vous avez atomique code> pour cette raison, qui sous les couvertures utilisent le Mots-clés volatile code>, ils font donc à peu près la même chose, mais ils vous permettent de gagner du temps et des efforts. P>

La chose que vous recherchez est atomicinteger code>, vous sont juste à ce sujet. Pour l'opération que vous essayez d'exécuter, c'est le meilleur choix. P>

Instances of classes `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, and `AtomicReference` each provide access and updates to a single variable of the corresponding type.
Each class also provides appropriate utility methods for that type.
For example, classes `AtomicLong` and AtomicInteger provide atomic increment methods.

The memory effects for accesses and updates of atomics generally follow the rules for volatiles:

get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.


3 commentaires

Je comprends votre réponse, mais la question n'est pas si simple. Je pense que le myintegerholder avec volatile n'est pas le fil-coffre-fort et j'ai présenté mon raisonnement. À mon avis, la bonne réponse doit faire référence à la spécification et à la définition de l'activité - avant la relation. Peut-être que je me trompe et que le titulaire du myinteger est le fil-sûr - mais dans ce cas, la réponse devrait expliquer quelle est la bonne façon de comprendre la définition de l'arrivée - avant la relation. Ou peut-être que le problème n'est pas avec le code (peut-être qu'il est correct), mais avec la spécification (peut-être que ce n'est pas assez clair).


"A informera B de tout ce qu'il a fait jusqu'à ce moment-là" - êtes-vous sûr? Est-ce que cela suit de la spécification? Dans la définition de la relation qui se produit - avant la relation, vous pouvez voir que l'écriture arrive - avant de lire, mais je n'ai pas vu le fragment disant que l'écriture arrive - avant une autre écrivie.


Je sais que Atomicinteger est similaire à l'entier volatile. Mais la question concerne vraiment la bonne compréhension de la relation qui se produit - avant la relation définie dans le Spécification de la langue Java



-1
votes

La question n'était pas facile pour moi, car je pensais (incorrectement) qui connaît tout ce qui concerne le arrive - avant la relation donne une compréhension complète du modèle de mémoire Java - et la sémantique de volatil .

J'ai trouvé la meilleure explication dans ce document: "JSR-133: Modèle de mémoire Javatm et spécification de thread"

Le fragment le plus pertinent du document ci-dessus est la section "7.3 Exécutions bien formées".

Le modèle de mémoire Java garantit que toutes les exécutions d'un programme sont bien formées . Une exécution est bien formée uniquement si elle

  • obéys arrive - avant la cohérence
  • obéys consistance de la commande de synchronisation
  • ... (d'autres conditions doivent également être vraies)

    arrive - avant la cohérence est généralement suffisante pour arriver à une conclusion sur le comportement du programme - mais pas dans ce cas, car une écriture volatile n'est pas arrive - avant une autre écriture volatile.

    Le timbre de myentifère avec volatile est Safe-Safe , mais la sécurité provient de la cohérence Synchronisation-Commande . .

    À mon avis, lorsque le thread B est sur le point de définir la valeur sur 7, A n'ignore pas B de tout ce qu'il a fait jusqu'à ce moment-là (comme l'une des autres réponses suggérées) - il n'indique que b à propos de la valeur de la valeur de la variable volatille. Le fil a informerait b sur tout (attribuer des valeurs à d'autres variables) si l'action prise par le thread b a été lu et non écrite (dans ce cas, il existerait le arrive - avant relation entre les actions prises par ces deux threads).


0 commentaires

0
votes

Le chapitre 17 de la spécification de langue Java définit la relation qui se produit - avant la relation sur des opérations de mémoire telles que lit que lit et écrit de variables partagées. Les résultats d'une écriture par un thread sont garantis pour être visibles par un autre fil uniquement si l'opération d'écriture se produit - avant l'opération de lecture.

  1. Les constructions synchronisées et volatiles, ainsi que les méthodes thread.start () et thread.join () peuvent se former auparavant des relations. En particulier: chaque action dans un fil arrive - avant chaque action dans ce fil qui vient plus tard dans l'ordre du programme.
  2. Un déverrouillage (bloc synchronisé ou méthode) d'un moniteur se produit - avant chaque serrure ultérieure (bloc synchronisé ou méthode entrée) de ce même moniteur. Et parce que l'arrivée avant la relation est transitif, toutes les actions d'un fil avant le déverrouillage arriver - avant toutes les actions à la suite de tout verrouillage du fil que moniteur.
  3. une écriture dans un champ volatile se produit - avant chaque lecture ultérieure de ce même champ. Écrit et les lectures de champs volatils ont similaire effets de cohérence de la mémoire en tant qu'entrant et sortant des moniteurs, mais faire ne comporte pas le verrouillage d'exclusion mutuelle.
  4. Un appel pour démarrer sur un thread arrive - avant toute action dans le fil de démarrage.
  5. Toutes les actions dans un fil se produisent - avant tout autre fil ne revient avec succès d'une jointure sur ce fil.

    Référence: http://developer.android.com/ Référence / Java / Util / simultané / paquet-sommaire.html

    de ma compréhension 3 signifie: Si vous écrivez (non basé sur le résultat de lecture) / lire, c'est bien. Si vous écrivez (basé sur le résultat de lecture, E.G., incrément) / Lire n'est pas bien. Depuis que volatile "n'entraîne pas le verrouillage mutuel d'exclusion"


0 commentaires

0
votes

Votre porte-myentifère avec volatile est le fil sûr. Mais Atomicinteger est préférable si vous faites un programme concurrent, car il fournit également de nombreuses opérations atomiques.

Considérez la séquence des événements suivants:

  1. Le fil a définit la valeur à 5.
  2. thread b définit la valeur à 7.
  3. thread c lit la valeur.

    Il résulte de la spécification de langue Java selon laquelle

    • "1" arrive-avant "3"
    • "2" arrive-avant "3"

      Mais je ne vois pas comment cela pourrait suivre de la spécification que "1" arrive-avant "2" alors je soupçonne que "1" n'arrive pas - avant "2".

      Je soupçonne que le fil C peut lire 7 ou 5. Je pense que la classe avec le Le mot-clé volatile n'est pas le thread-coffre-fort

      Vous avez raison ici que "1" arrive - avant "3" et "2" arrive - avant "3". "1" ne se passe pas - avant "2", mais cela ne signifie pas que ce n'est pas le fil-faire. La chose est que l'exemple que vous avez fourni est ambigu. Si vous dites "Définit la valeur à 5" "," Définit la valeur sur 7 "", "lit la valeur" se produit de manière séquentielle, vous pouvez toujours lire la valeur de 7. et il est absurdité de les mettre dans des threads différents. Mais si vous dites que 3 threads s'exécutent simultanément sans séquence, vous pouvez même obtenir la valeur de 0, car "lit la valeur" pourrait se produire d'abord. Mais ce n'est rien avec le fil-faire-coffre-fort, il n'y a pas d'ordre s'attendant à partir des 3 actions.


0 commentaires