2010-08-16 7 views
17

J'ai deux threads. On invoque la méthode de mise à jour d'une classe qui modifie une variable. Un autre appelle la méthode de mise à jour d'une classe qui lit la variable. Un seul thread écrit et un (ou plusieurs) threads lisent cette variable. Que dois-je faire en termes de concurrence, étant donné que je suis novice en matière de multi-threading?Java partage une variable entre deux threads

public class A 
{ 
    public int variable; // Does this need to be volatile? 
     // Not only int, could also be boolean or float. 
    public void update() 
    { 
     // Called by one thread constantly 
     ++variable; 
     // Or some other algorithm 
     variable = complexAlgorithm(); 
    } 
} 

public class B 
{ 
    public A a; 
    public void update() 
    { 
     // Called by another thread constantly 
     // I don't care about missing an update 
     int v = a.variable; 
     // Do algorithm with v... 
    } 
} 

Merci,

+2

La plupart des réponses ci-dessous supposent que vous effectuez une manipulation d'entier qui peut être gérée par la classe 'AtomicInteger'. Pour quelque chose de plus complexe, regardez un bloc 'synchronized' ou' java.util.conccurent.locks.Lock' – justkt

Répondre

17

S'il y a un seul et unique thread qui écrit à variable, vous pouvez vous en sortir en le faisant volatile. Sinon, voir la réponse avec AtomicInteger.

Seul volatile fonctionnera dans le cas d'un seul thread d'écriture car il n'y a qu'un seul thread d'écriture, donc il a toujours la bonne valeur de variable.

+0

C'était mon point. Je sais qu'un seul thread le modifie mais il pourrait y avoir beaucoup de threads le lisant. – Dave

+0

@Dave - bien, c'est pourquoi j'ai posté cette réponse. Si votre multithread est simple, un seul thread écrit et vous n'avez qu'une seule variable à écrire pour les autres threads à lire, vous n'avez pas besoin d'une solution complexe, la variable volatile volatile fera l'affaire. Dans un cas général, vous voudrez probablement des verrous, synchonized ou AtomicInteger. Mais votre question était assez spécifique sur le nombre de threads écrivain et le nombre de variables impliquées. Ne soyez pas intimidé par les votes sur les autres réponses. Si ma solution répond à vos besoins, acceptez-la. – hidralisk

+0

Merci beaucoup, j'avais juste besoin d'un deuxième avis. Je ne connaissais pas non plus les variables Atomic et autres goodies dans le paquet de simultanéité que je suis heureux que les gens ici aient eu la gentillesse d'expliquer. Cela pourrait s'avérer utile pour moi dans le futur. – Dave

8

Non seulement devrait être variablevolatile, mais vous voulez aussi protéger votre fonction update avec some sort of synchronization depuis ++variable n'est pas un appel atomique. Il s'agit, après tout, de sucre syntaxique pour

variable = variable + 1; 

qui n'est pas atomique.

Vous devriez également inclure tous les appels qui lisent une variable dans un lock.

Vous pouvez également utiliser un AtomicInteger. Il a été fait pour ce genre de chose (pour des opérations entières).

public class A 
{ 
    // initially had said volatile wouldn't affect this variable because 
    // it is not a primitive, but see correction in comments 
    public final AtomicInteger variable; // see comments on this issue of why final 
    public void update() 
    { 
     // Called by one thread constantly 
     variable.getAndIncrement(); // atomically adds one 
    } 
    public int retrieveValue() 
    { 
     return variable.get(); // gets the current int value safely 
    } 
} 

public class B 
{ 
    public A a; 
    public void update() 
    { 
     // Called by another thread constantly 
     int v = a.retrieveValue(); 
     // Do algorithm with v... 
    } 
} 

Pour les algorithmes plus complexes, comme le suppose votre modification récente, utilisez la synchronisation ou les verrous.

+0

En disant "une sorte de verrou", vous voulez dire "mettez-le dans un bloc synchronisé ou faites que la méthode soit synchronisée" n'est-ce pas? En outre, +1 avec l'AtomicInteger – Riduidel

+0

Ou utilisez un 'java.util.concurrent.Lock' de quelque sorte. J'ai tendance à préférer cela à «synchronisé» pour plus d'expressivité - j'aime particulièrement ReadWriteLock. – justkt

+2

Votre commentaire "volatile n'affectera pas cela, ce n'est pas une primitive" est trompeur. Cela n'a rien à voir avec le fait que le champ soit primatif, mais tout à voir avec le fait que 'variable' n'est plus réassigné. Faire 'variable' final serait conseillé ici. –

9

Dans ce cas j'utiliserais un AtomicInteger, cependant la réponse généralisée est que l'accès à la variable devrait être protégé par un bloc synchronisé, ou en utilisant une autre partie du paquetage java.util.concurrent.

Quelques exemples:

Utilisation synchronisée

public class A { 
    public final Object variable; 
    public void update() { 
     synchronized(variable) { 
      variable.complexAlgorithm(); 
     } 
    } 
} 

public class B { 
    public A a; 
    public void update() { 
     sychronized(a.variable) { 
      consume(a.variable); 
     } 
    } 
} 

En utilisant java.util.concurrent

public class A { 
    public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 
    public final Object variable; 
    public void update() { 
     lock.writeLock().lock(); 
     try { 
      variable.complexAlgorithm(); 
     } finally { 
      lock.writeLock().unlock(); 
     } 
    } 
} 

public class B { 
    public A a; 
    public void update() { 
     a.lock.readLock().lock(); 
     try { 
      consume(a.variable); 
     } finally { 
      a.lock.readLock().unlock(); 
     } 
    } 
} 
+0

Pouvez-vous expliquer pourquoi pas variable.getWriteLock(). Lock() dans la classe A? – Radu

+0

Vous pouvez uniquement synchroniser sur un objet, et cet objet doit être final. Dans cet exemple, la synchronisation est effectuée via une implémentation de ReadWriteLock (plusieurs threads peuvent donc être lus simultanément) - voir http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock .html –

4

Utilisez AtomicInteger ou synchronize l'accès à l'abri.

+0

pouvez-vous s'il vous plaît expliquer ce que vous voulez dire par synchroniser? Comme là où il devrait aller, c'est un peu déroutant pour moi. – Dave

+0

@Dave - http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html devrait vous aider avec la synchronisation Java de base. – justkt

Questions connexes