2009-12-05 13 views
8

Tengo dos matrices, y necesito sincronizar el acceso a ellas a través de subprocesos. Voy a ponerlos en un bloque sincronizado. El problema es que solo puedo pasar uno de ellos para 'sincronizar' una vez.java sincronized block para más de 1 objetos?

¿Cómo me aseguro de que el acceso a ambas matrices esté sincronizado? ¿Los puse en una clase y creé un objeto de ella? O accedo a la otra matriz solo en el bloque sincronizado, y esto se ocupa de tener acceso sincronizado a ella?

Gracias,

+0

Ponerlos en una nueva clase puede ayudar a aclarar lo que quiere hacer, por lo que lo recomendaría. Sin embargo, eso no afecta la seguridad del hilo en absoluto. Me gusta la respuesta que usa bloqueos explícitos (a continuación). –

Respuesta

20

lo que haga no hacer esto:

synchronized (array1) { 
    synchronized (array2) { 
    // do stuff 
    } 
} 

Ésta es probable que conduzca a deadlock menos que esté muy cuidadoso. Si realiza este enfoque, debe asegurarse de tener un orden parcial invariable sobre los objetos: Google "Filosofos del comedor" para la discusión de las trampas.

Básicamente lo que tiene que hacer es crear un objeto de bloqueo que va a utilizar si desea acceder a cualquiera matriz y luego utilizar eso para todos de acceso a conjunto. Es de grano grueso pero seguro. Se podía hacerlo de esta manera:

public static class TwoArrays { 
    private int[] array1 = ... 
    private int[] array2 = ... 
    private final Object LOCK = new Object(); 

    public void doUpdate() { 
    synchronized (LOCK) { 
     ... 
    } 
    } 
} 

Si se necesita un método más fino que desea utilizar los servicios públicos concurrentes del Java 5+ tales como ReadWriteLock pero esto va a ser más complicado de implementar y propenso a errores.

+1

También podría hacer 'doUpdate' sincronizado, entonces, en lugar de tener la complejidad añadida del objeto' LOCK'. – skaffman

+3

En realidad, no, es una buena práctica no exponer sus cerraduras, que es lo que está haciendo cuando usa esto como cerradura. – cletus

+0

esto hace que surja una pregunta: el uso del bloque sincronizado anidado puede llevar a un interbloqueo, en caso de que haya otra sincronización en los mismos objetos. Pero, ¿pasaría si solo está presente el código anterior? Ningún hilo podría adquirir el monitor de array2 si aún no tiene el monitor de array1. Y si tiene el monitor de array1, ningún otro hilo puede tener el monitor de array2. ¿Tengo un agujero en mi razonamiento? – Bozho

11

cosas Antes de Java 5, habría escrito así:

// pre Java 5 code: 
Object lock = new Object(); 
// ... 
synchronized(lock) { 
    // do something that requires synchronized access 
} 

Pero desde Java 5, usaría clases de java.util.concurrent.locks (personalmente, no encuentro esto más complicado o error -prone):

// Java 5 Code Using Locks 
Lock lock = // ... 
lock.lock(); 
try { 
    // do something that requires synchronized access 
} 
finally { 
    lock.unlock(); 
} 

Si necesita lectura-escritura de bloqueo, aquí está implementado ejemplo el uso de bloqueos de lectura y escritura de Java 5:

private ReadWriteLock rwl = new ReentrantReadWriteLock(); 
private Lock rLock = rwl.readLock(); 
private Lock wLock = rwl.writeLock(); 

private List<String> data = new ArrayList<String>(); 

public String getData(int index) { 
    rLock.lock(); 
    try { 
     return data.get(index); 
    } finally { 
     rLock.unlock(); 
    } 
} 

public void addData(int index, String element) { 
    wLock.lock(); 
    try { 
     data.add(index, element); 
    } finally { 
     wLock.unlock(); 
    } 
} 

Por supuesto, adáptelo a sus necesidades.