2010-08-16 59 views
17

Tengo dos hilos. Uno invoca el método de actualización de una clase que modifica una variable. Otro invoca el método de actualización de una clase que lee la variable. Solo un hilo escribe y uno (o más) hilos lee esa variable. ¿Qué debo hacer en términos de concurrencia, ya que soy nuevo en multi-threading?Java comparte una variable entre dos hilos

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... 
    } 
} 

Gracias,

+2

Muchas de las respuestas siguientes suponen que está realizando una manipulación de enteros que puede manejar la clase 'AtomicInteger'. Para algo más complejo, mire un bloque 'sincronizado' o el' java.util.conccurent.locks.Lock' – justkt

Respuesta

17

Si hay un único hilo que escribe en variable, puede salirse con la suya haciéndolo volatile. De lo contrario, vea la respuesta con AtomicInteger.

Solo volatile funcionará en el caso de un solo hilo de escritura porque solo hay un hilo de escritura por lo que siempre tiene el valor correcto de variable.

+0

Ese fue mi punto. Sé que solo un hilo lo modifica, pero podría haber muchos hilos que lo lean. – Dave

+0

@Dave - bueno, esta es la razón por la que publiqué esta respuesta. Si su multi-threading es simple, solo se escribe un thread y solo tiene una variable que escribe para que otros hilos lo lean, no necesita una solución compleja, la variable int volátil lo hará. En un caso general, es probable que desee Bloqueos, sincronizados o AtomicInteger. Pero su pregunta fue bastante específica sobre el número de hilos de escritor y el número de variables involucradas. No se deje intimidar por los votos en otras respuestas. Si mi solución satisface sus necesidades, acéptela. – hidralisk

+0

Muchas gracias, solo necesitaba una segunda opinión. Tampoco sabía acerca de las variables atómicas y otras ventajas en el paquete de simultaneidad que estoy contento de que la gente haya tenido la amabilidad de explicar. Puede ser valioso para mí en el futuro. – Dave

8

No sólo debe ser variablevolatile, pero también se desea proteger su función update con some sort of synchronization desde ++variable no es una llamada atómica. Es, después de todo, simplemente azúcar sintáctica para

variable = variable + 1; 

que no es atómico.

También debe ajustar cualquier llamada que lea la variable en un lock de algún tipo.

Como alternativa, utilice AtomicInteger. Fue hecho para este tipo de cosas (solo para operaciones enteras).

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... 
    } 
} 

Para los algoritmos más complejos, como asume su edición reciente, use sincronización o bloqueos.

+0

Al decir "algún tipo de bloqueo", quiere decir "ponerlo en un bloque sincronizado o sincronizar el método" "¿No es así? Además, +1 con AtomicInteger – Riduidel

+0

O utilice un 'java.util.concurrent.Lock' de algún tipo. Tiendo a preferir eso sobre 'sincronizado' para más expresividad. Me gusta especialmente 'ReadWriteLock'. – justkt

+2

Su comentario "volátil no afectará esto, no es primitivo" es engañoso. No tiene nada que ver con si el campo es primitivo, sino todo con el hecho de que 'variable' ya no se reasigna. Haciendo la 'variable' final sería aconsejado aquí. –

9

En este caso usaría AtomicInteger, sin embargo, la respuesta generalizada es que el acceso a la variable debe estar protegido por un bloque sincronizado o mediante el uso de otra parte del paquete java.util.concurrent.

Un par de ejemplos:

Uso sincronizados

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

Usando 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

¿Pueden ustedes explicar por qué no variable.getWriteLock(). Lock() en la clase A? – Radu

+0

Solo se puede sincronizar en un objeto, y ese objeto debe ser final. En este ejemplo, la sincronización se realiza a través de una implementación de ReadWriteLock (por lo que varios subprocesos podrían leerse al mismo tiempo); consulte http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock .html –

4

Uso AtomicInteger o synchronize el acceso a estar a salvo.

+0

¿me puede explicar qué quiere decir sincronizar? Al igual que donde debería ir, es un poco confuso para mí. – Dave

+0

@Dave - http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html debería ayudarlo con la sincronización básica de Java. – justkt

Cuestiones relacionadas