2010-08-16 19 views
17

Ich habe zwei Threads. Man ruft die Aktualisierungsmethode einer Klasse auf, die eine Variable modifiziert. Ein anderes ruft die Update-Methode einer Klasse auf, die die Variable liest. Nur ein Thread schreibt und ein (oder mehrere) Threads lesen diese Variable. Was muss ich in Bezug auf Nebenläufigkeit tun, da ich neu im Multithreading bin?Java teilen eine Variable zwischen zwei 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... 
    } 
} 

Danke,

+2

Viele der folgenden Antworten gehen davon aus, dass Sie Integer-Manipulationen durchführen, die von der Klasse "AtomicInteger" gehandhabt werden können. Für etwas Komplexeres, schaue auf einen 'synchronisierten' Block oder die' java.util.conccurent.locks.Lock' – justkt

Antwort

17

Wenn es einen und nur einen Thread gibt, der in variable schreibt, können Sie es schaffen volatile zu machen. Ansonsten siehe die Antwort mit AtomicInteger.

Nur volatile funktioniert bei nur einem Schreib-Thread, da es nur einen Schreib-Thread gibt, so dass es immer den richtigen Wert von variable hat.

+0

Das war mein Punkt. Ich weiß, dass nur ein Thread es ändert, aber es könnte viele Threads geben, die es lesen. – Dave

+0

@Dave - nun, deshalb habe ich diese Antwort gepostet. Wenn Ihr Multithreading einfach ist, schreibt nur ein Thread und Sie haben nur eine Variable, in die geschrieben wird, damit die anderen Threads lesen können. Sie benötigen keine komplexe Lösung, die volatile int-Variable. In einem allgemeinen Fall würden Sie wahrscheinlich Locks, Synchronized oder AtomicInteger wollen. Aber Ihre Frage war ziemlich spezifisch für die Anzahl der Writer-Threads und die Anzahl der beteiligten Variablen. Lassen Sie sich nicht durch die Stimmen anderer Antworten einschüchtern. Wenn meine Lösung Ihren Anforderungen entspricht, akzeptieren Sie sie. – hidralisk

+0

Vielen Dank, ich brauchte nur eine zweite Meinung. Ich wusste auch nie über atomische Variablen und andere Leckerbissen im Nebenläufigkeitspaket, dass ich froh bin, dass die Leute hier freundlich genug waren, das zu erklären. Es könnte sich für mich in der Zukunft als wertvoll erweisen. – Dave

8

sollte variable nicht nur volatile, aber Sie wollen auch mit some sort of synchronization seit ++variable Ihre update Funktion zu schützen, ist nicht ein Atom Anruf. Es ist schließlich nur syntaktischer Zucker für

die nicht atomar ist.

Sie sollten auch alle Anrufe, die Variable in einem lock von irgendeiner Art lesen, umbrechen.

Alternativ können Sie auch AtomicInteger verwenden. Es wurde für diese Art von Sache gemacht (für nur ganzzahlige Operationen).

Für die komplexeren Algorithmen, wie Ihre kürzliche Bearbeitung annimmt, verwenden Sie Synchronisation oder Sperren.

+0

Mit dem Sprichwort "irgendeine Art von Sperre" meinst du "setze es in einen synchronisierten Block oder mach die Methode synchronisiert "Ist es nicht? Außerdem +1 mit dem AtomicInteger – Riduidel

+0

Oder verwenden Sie eine 'java.util.concurrent.Lock' von irgendeiner Art. Ich ziehe es vor, das über 'synchronisierte' für mehr Ausdruckskraft vorzuziehen - ich mag' ReadWriteLock' besonders. – justkt

+2

Ihr Kommentar "flüchtig wird dies nicht beeinflussen, es ist kein primitives" ist irreführend. Es hat nichts damit zu tun, ob das Feld ein Primativ ist, sondern alles damit zu tun hat, dass "Variable" nicht mehr neu zugewiesen wird. Das 'variable' Finale wäre hier zu empfehlen. –

9

In diesem Fall würde ich eine AtomicInteger verwenden, aber die generalisierte Antwort ist, dass der Zugriff auf die Variable durch einen synchronisierten Block oder durch die Verwendung eines anderen Teils des java.util.concurrent-Pakets geschützt werden sollte.

Ein paar Beispiele:

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); 
     } 
    } 
} 

synchronisiert Verwenden java.util.concurrent Mit

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

Können Sie bitte erklären, warum nicht variable.getWriteLock(). Lock() in Klasse A? – Radu

+0

Sie können nur für ein Objekt synchronisieren, und dieses Objekt muss endgültig sein. In diesem Beispiel erfolgt die Synchronisation über eine Implementierung von ReadWriteLock (so dass mehrere Threads gleichzeitig lesen können) - siehe http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock .html –

4

Verwenden AtomicInteger oder synchronize den Zugriff sicher zu sein.

+0

kannst du bitte erklären, was du mit synchronisieren meinst? Wie, wo es hingehen sollte, ist es ein bisschen verwirrend für mich. – Dave

+0

@Dave - http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html sollte Ihnen mit grundlegenden Java-Synchronisation helfen. – justkt

Verwandte Themen