2012-06-30 10 views
12

Me he encontrado con un código como las siguientes varias vecessincronizada con un objeto ficticio en lugar de esta

class Foo { 
    private Object lock = new Object(); 

    public void doSomething() { 
     synchronized(lock) { 
     ... 

Lo que me interesa es por qué se crea un objeto de bloqueo en lugar de escribir synchronized(this)? ¿Está ahí para permitir compartir el bloqueo? Recuerdo vagamente haber leído que se trata de una optimización. ¿Es eso cierto? Además, ¿tiene sentido, en algún contexto, tener el bloqueo declarado como final?

+0

Esta pregunta se responde aquí: http://stackoverflow.com/a/3369303/1343161 – Keppil

Respuesta

23
  1. Sincronización en la this se desanima porque si el objeto en sí mismo se utiliza como un bloqueo desde el exterior se rompería la sincronización interna. Además, recuerde que los métodos synchronized también usan this como un bloqueo, que puede causar un efecto no deseado.
  2. Se recomienda declarar el bloqueo final para evitar una situación en la que un objeto de bloqueo se reasigne dentro de un bloque synchronized, haciendo que diferentes subprocesos vean diferentes objetos de bloqueo. Ver esta otra pregunta: Locking on a mutable object - Why is it considered a bad practice?
+0

1; te mereces una bonita insignia de respuesta :) – GETah

3

imaginar un escenario en el que tiene thread1 y thread2 acceso method1, thread3 y thread4 acceso method2. Sincronización en la this bloquearía thread3 y thread4 si thread1 o thread2 están accediendo method1 que no debería suceder como thread3 y thread4 no tienen nada que ver con method1. Una optimización para esto es usar dos bloqueos diferentes en lugar de bloquear en toda la instancia de clase.

Aquí es un buen párrafo que encontré en JavaDoc que refleja esto:

declaraciones sincronizados también son útiles para mejorar la concurrencia con sincronización de grano fino. Supongamos, por ejemplo, que la clase MsLunch tiene dos campos de instancia, c1 y c2, que nunca se usan juntos. Todos actualizaciones de estos campos deben estar sincronizados, pero no hay razón para prevenir una actualización de c1 de ser intercalada con una actualización de C2 - y al hacerlo reduce la simultaneidad mediante la creación innecesaria bloqueo

+0

+1 para ti también. Un buen ejemplo de por qué las cerraduras deben ser de grano fino. – Tudor

0

considerar el uso de una cerradura desde el paquete java.util.concurrent
Esto puede proporcionar un bloqueo más optimizado, por ejemplo, el uso de ReadWriteLock permitirá el acceso de todos los lectores sin esperar.

0

Aquí está el ejemplo de trabajo completo de "ReentrantReadWriteLock".

public class DataReader { 
private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 
private static final Lock read = readWriteLock.readLock(); 
private static final Lock write = readWriteLock.writeLock(); 
public static void loadData() { 
    try { 
    write.lock(); 
    loadDataFromTheDB()); 
    } finally { 
    write.unlock(); 
    } 
} 

public static boolean readData() { 
    try { 
    read.lock(); 
    readData(); 
    } finally { 
    read.unlock(); 
    } 
} 

public static List loadDataFromTheDB() { 
    List list = new ArrayList(); 
    return list; 
} 

    public static void readData() throws DataServicesException { 
    //Write reading logic 
    } 
} 
Cuestiones relacionadas