¿Hay una ventaja de usar un Método Sincronizado en lugar de un Bloque Sincronizado?


¿Puede alguien decirme la ventaja del método sincronizado sobre el bloque sincronizado con un ejemplo?

Author: Mahozad, 2009-02-22

22 answers

¿alguien Puede decirme la ventaja del método sincronizado sobre el bloque sincronizado con un ejemplo? Gracias.

No hay una clara ventaja de usar el método sincronizado sobre el bloque.

Quizás el único ( pero no lo llamaría una ventaja ) es que no necesita incluir la referencia de objeto this.

Método:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

Bloque:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

¿Ves? Ninguna ventaja en absoluto.

Los bloques tienen ventajas sobre los métodos sin embargo, sobre todo en la flexibilidad porque se puede utilizar otro objeto como bloqueo, mientras que la sincronización del método bloquearía todo el objeto.

Comparar:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

Vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

También si el método crece, puede mantener la sección sincronizada separada:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}
 397
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-14 15:15:51

La única diferencia real es que un bloque sincronizado puede elegir en qué objeto se sincroniza. Un método sincronizado solo puede usar 'this' (o la instancia de clase correspondiente para un método de clase sincronizado). Por ejemplo, estos son semánticamente equivalentes:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

Este último es más flexible ya que puede competir por el bloqueo asociado de cualquier objeto, a menudo una variable miembro. También es más granular porque podría tener código concurrente ejecutándose antes y después el bloque, pero todavía dentro del método. Por supuesto, podría usar un método sincronizado fácilmente refactorizando el código concurrente en métodos separados no sincronizados. Utilice lo que haga que el código sea más comprensible.

 136
Author: jcrossley3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-22 03:46:39

Método sincronizado

Ventajas:

  • Su IDE puede indicar los métodos sincronizados.
  • La sintaxis es más compacta.
  • Fuerza a dividir los bloques sincronizados en métodos separados.

Contras:

  • Se sincroniza con esto y así hace posible que los forasteros también se sincronicen con él.
  • Es más difícil mover código fuera del bloque sincronizado.

Bloque sincronizado

Ventajas:

  • Permite utilizar un variable privada para la cerradura y forzando así la cerradura a permanecer dentro de la clase.
  • Los bloques sincronizados se pueden encontrar buscando referencias a la variable.

Contras:

  • La sintaxis es más complicada y por lo tanto hace que el código sea más difícil de leer.

Personalmente prefiero usar métodos sincronizados con clases enfocadas solo a lo que necesita sincronización. Tal clase debe ser lo más pequeña posible y por lo tanto debe ser fácil de revisar la sincronización. Otros no deberían tener que preocuparse por la sincronización.

 75
Author: iny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-09 19:22:00

La principal diferencia es que si usas un bloque sincronizado puedes bloquear un objeto que no sea este lo que permite ser mucho más flexible.

Supongamos que tiene una cola de mensajes y varios productores y consumidores de mensajes. No queremos que los productores interfieran entre sí, pero los consumidores deberían poder recuperar mensajes sin tener que esperar a los productores. Así que simplemente creamos un objeto

Object writeLock = new Object();

Y a partir de ahora cada vez que un productor quiera añadir un nuevo mensaje que acabamos de fijar en que:

synchronized(writeLock){
  // do something
}

Así que los consumidores todavía pueden leer, y los productores estarán bloqueados.

 35
Author: cdecker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-19 10:44:44

Método Sincronizado

Los métodos sincronizados tienen dos efectos.
En primer lugar, cuando un subproceso está ejecutando un método sincronizado para un objeto, todos los demás subprocesos que invocan métodos sincronizados para el mismo bloque de objeto (suspenden la ejecución) hasta que el primer subproceso termine con el objeto.

En segundo lugar, cuando un método sincronizado sale, establece automáticamente una relación sucede-antes con cualquier invocación posterior de un método sincronizado para el mismo objeto. Esto garantiza que los cambios en el estado del objeto sean visibles para todos los subprocesos.

Tenga en cuenta que los constructores no se pueden sincronizar - usar la palabra clave sincronizada con un constructor es un error de sintaxis. Sincronizar constructores no tiene sentido, porque solo el hilo que crea un objeto debe tener acceso a él mientras se está construyendo.

Sentencia sincronizada

A diferencia de los métodos sincronizados, las sentencias sincronizadas deben especificar objeto que proporciona el bloqueo intrínseco: La mayoría de las veces uso esto para sincronizar el acceso a una lista o mapa, pero no quiero bloquear el acceso a todos los métodos del objeto.

Q: Bloqueos Intrínsecos y Sincronización La sincronización se construye alrededor de una entidad interna conocida como bloqueo intrínseco o bloqueo de monitor. (La especificación API a menudo se refiere a esta entidad simplemente como un " monitor.") Los bloqueos intrínsecos juegan un papel en ambos aspectos de la sincronización: imponer el acceso exclusivo al estado de un objeto y el establecimiento sucede - antes de las relaciones que son esenciales para la visibilidad.

Cada objeto tiene un bloqueo intrínseco asociado a él. Por convención, un hilo que necesita acceso exclusivo y consistente a los campos de un objeto tiene que adquirir el bloqueo intrínseco del objeto antes de acceder a ellos, y luego liberar el bloqueo intrínseco cuando se hace con ellos. Se dice que un hilo posee la cerradura intrínseca entre el momento en que ha adquirido la cerradura y la liberó. Mientras un hilo posea un bloqueo intrínseco, ningún otro hilo puede adquirir el mismo bloqueo. El otro hilo se bloqueará cuando intente adquirir el bloqueo.

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

Comprobación cruzada de diferentes salidas con método sincronizado, bloque y sin sincronización.

 29
Author: sudheer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-07 16:15:36

Nota: static los métodos y bloques sincronizados funcionan en el objeto de clase.

public class MyClass {
   // locks MyClass.class
   public static synchronized void foo() {
// do something
   }

   // similar
   public static void foo() {
      synchronized(MyClass.class) {
// do something
      }
   }
}
 27
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-22 03:30:31

Cuando el compilador java convierte su código fuente en código de bytes, maneja métodos sincronizados y bloques sincronizados de manera muy diferente.

Cuando la JVM ejecuta un método sincronizado, el subproceso de ejecución identifica que la estructura method_info del método tiene el indicador ACC_SYNCHRONIZED establecido, luego adquiere automáticamente el bloqueo del objeto, llama al método y libera el bloqueo. Si se produce una excepción, el subproceso libera automáticamente el bloqueo.

Sincronización de un método block, por otro lado, omite el soporte integrado de la JVM para adquirir el bloqueo y el manejo de excepciones de un objeto y requiere que la funcionalidad se escriba explícitamente en código de bytes. Si lee el código de bytes de un método con un bloque sincronizado, verá más de una docena de operaciones adicionales para administrar esta funcionalidad.

Esto muestra llamadas para generar tanto un método sincronizado como un bloque sincronizado:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

    public int synchronizedBlockGet() {
        synchronized( this ) {
            return i;
        }
    }
}

El método synchronizedMethodGet() genera el siguiente byte código:

0:  aload_0
1:  getfield
2:  nop
3:  iconst_m1
4:  ireturn

Y aquí está el código de bytes del método synchronizedBlockGet():

0:  aload_0
1:  dup
2:  astore_1
3:  monitorenter
4:  aload_0
5:  getfield
6:  nop
7:  iconst_m1
8:  aload_1
9:  monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow

Una diferencia significativa entre el método sincronizado y el bloque es que, el bloque sincronizado generalmente reduce el alcance del bloqueo. Como el alcance del bloqueo es inversamente proporcional al rendimiento, siempre es mejor bloquear solo la sección crítica del código. Uno de los mejores ejemplos de uso de bloques sincronizados es el bloqueo doble comprobado en el patrón Singleton donde en lugar de bloquear todo el método getInstance() solo bloquee la sección crítica del código que se usa para crear una instancia de Singleton. Esto mejora el rendimiento drásticamente porque el bloqueo solo se requiere una o dos veces.

Al usar métodos sincronizados, tendrá que tener especial cuidado si mezcla ambos métodos sincronizados estáticos y no estáticos.

 17
Author: Mohammad Adil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-23 08:05:58

La mayoría de las veces uso esto para sincronizar el acceso a una lista o mapa, pero no quiero bloquear el acceso a todos los métodos del objeto.

En el siguiente código, un subproceso que modifique la lista no bloqueará la espera de un subproceso que esté modificando el mapa. Si los métodos se sincronizaran en el objeto, entonces cada método tendría que esperar, aunque las modificaciones que están haciendo no entrarían en conflicto.

private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();

public void put( String s, Bar b ) {
  synchronized( myMap ) {
    myMap.put( s,b );
    // then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public void hasKey( String s, ) {
  synchronized( myMap ) {
    myMap.hasKey( s );
  }
}

public void add( Foo f ) {
  synchronized( myList ) {
    myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public Thing getMedianFoo() {
  Foo med = null;
  synchronized( myList ) {
    Collections.sort(myList);
    med = myList.get(myList.size()/2); 
  }
  return med;
}
 12
Author: Clint,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-22 07:04:38

Con bloques sincronizados, puede tener múltiples sincronizadores, de modo que múltiples cosas simultáneas pero no conflictivas pueden continuar al mismo tiempo.

 6
Author: Paul Tomblin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-22 03:19:18

Los métodos sincronizados se pueden comprobar utilizando la API de reflexión. Esto puede ser útil para probar algunos contratos, como todos los métodos en el modelo están sincronizados.

El siguiente fragmento imprime todos los métodos sincronizados de Hashtable:

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}
 6
Author: Kojotak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 08:45:10

Nota importante sobre el uso del bloque sincronizado: ¡cuidado con lo que usas como objeto de bloqueo!

El fragmento de código de user2277816 anterior ilustra este punto en el que se usa una referencia a un literal de cadena como objeto de bloqueo. Tenga en cuenta que los literales de cadena se internan automáticamente en Java y debería comenzar a ver el problema: ¡cada pieza de código que se sincroniza en el "bloqueo" literal, comparte el mismo bloqueo! Esto puede conducir fácilmente a estancamientos con piezas completamente no relacionadas de codificar.

No es solo objetos de cadena con los que debe tener cuidado. Las primitivas en caja también son un peligro, ya que el autoboxing y los métodos valueOf pueden reutilizar los mismos objetos, dependiendo del valor.

Para más información ver: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

 5
Author: Søren Boisen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-12 11:41:31

A menudo usar un bloqueo en un nivel de método es demasiado grosero. Por qué bloquear un fragmento de código que no tiene acceso a ningún recurso compartido bloqueando un método completo. Dado que cada objeto tiene un bloqueo, puede crear objetos ficticios para implementar la sincronización a nivel de bloque. El nivel de bloque es más eficiente porque no bloquea todo el método.

Aquí un ejemplo

Nivel del método

class MethodLevel {

  //shared among threads
SharedResource x, y ;

public void synchronized method1() {
   //multiple threads can't access
}
public void synchronized method2() {
  //multiple threads can't access
}

 public void method3() {
  //not synchronized
  //multiple threads can access
 }
}

Bloque Nivel

class BlockLevel {
  //shared among threads
  SharedResource x, y ;

  //dummy objects for locking
  Object xLock = new Object();
  Object yLock = new Object();

    public void method1() {
     synchronized(xLock){
    //access x here. thread safe
    }

    //do something here but don't use SharedResource x, y
    // because will not be thread-safe
     synchronized(xLock) {
       synchronized(yLock) {
      //access x,y here. thread safe
      }
     }

     //do something here but don't use SharedResource x, y
     //because will not be thread-safe
    }//end of method1
 }

[Editar]

For Collection like Vector and Hashtable they are synchronized when ArrayList or HashMap are not and you need set synchronized keyword or invoke Collections synchronized method:

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
 5
Author: Maxim Shoustin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-10 11:41:40

El método sincronizado se utiliza para bloquear todos los objetos El bloque sincronizado se usa para bloquear objetos específicos

 4
Author: kishore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-14 06:35:56

La única diferencia : los bloques sincronizados permiten el bloqueo granular a diferencia del método sincronizado

Básicamente synchronized se han utilizado bloques o métodos para escribir código seguro de subprocesos evitando errores de inconsistencia de memoria.

Esta pregunta es muy antigua y muchas cosas han cambiado durante los últimos 7 años. Se han introducido nuevas construcciones de programación para la seguridad de los hilos.

Puede lograr la seguridad del subproceso mediante el uso de API de concurrencia avanzada en lugar de synchronied bloque. Esta página de documentación proporciona buenas construcciones de programación para lograr la seguridad del hilo.

Bloquear Objetos admite expresiones de bloqueo que simplifican muchas aplicaciones simultáneas.

Ejecutores defina una API de alto nivel para iniciar y administrar subprocesos. Implementaciones ejecutoras proporcionadas por java.útil.concurrente proporcione la gestión del grupo de subprocesos adecuada para aplicaciones a gran escala.

Concurrente Colecciones facilita la gestión de grandes colecciones de datos y puede reducir en gran medida la necesidad de sincronización.

Variables Atómicas tenga características que minimicen la sincronización y ayuden a evitar errores de consistencia de memoria.

Localrandom de rosca (en JDK 7) proporciona una generación eficiente de números pseudoaleatorios a partir de múltiples hilos.

Mejor reemplazo para sincronizado es ReentrantLock , que utiliza Lock API

Un bloqueo de exclusión mutua reentrante con el mismo comportamiento básico y semántica que el bloqueo de monitor implícito al que se accede utilizando métodos y sentencias sincronizados, pero con capacidades extendidas.

Ejemplo con bloqueos:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Refiérase a java.útil.concurrent and java.útil.concurrente.atomic paquetes también para otras construcciones de programación.

Refiérase también a esta pregunta relacionada:

Sincronización vs Lock

 4
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-14 15:47:36

En general, estos son en su mayoría los mismos que no sean explícitos sobre el monitor del objeto que se está utilizando vs el implícito este objeto. Un inconveniente de los métodos sincronizados que creo que a veces se pasa por alto es que al usar la referencia "this" para sincronizar está dejando abierta la posibilidad de que los objetos externos se bloqueen en el mismo objeto. Eso puede ser un error muy sutil si te encuentras con él. La sincronización en un objeto explícito interno u otro campo existente puede evitar esto problema, encapsulando completamente la sincronización.

 3
Author: Alex Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-22 20:28:59

Como ya se ha dicho aquí bloque sincronizado puede utilizar variable definida por el usuario como objeto de bloqueo, cuando la función sincronizada utiliza solo "esto". Y, por supuesto, puede manipular con áreas de su función que deben sincronizarse. Pero todo el mundo dice que no hay diferencia entre la función sincronizada y el bloque que cubre toda la función usando "esto" como objeto de bloqueo. Eso no es cierto, la diferencia está en el código de bytes que se generará en ambas situaciones. En caso de uso de bloque sincronizado debe ser variable local asignada que contiene referencia a "this". Y como resultado tendremos un tamaño un poco más grande para la función (no es relevante si solo tiene un número reducido de funciones).

Una explicación más detallada de la diferencia se puede encontrar aquí: http://www.artima.com/insidejvm/ed2/threadsynchP.html

 2
Author: Roman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 08:43:36

En el caso de métodos sincronizados, el bloqueo se adquiere en un Objeto. Pero si va con bloque sincronizado tiene una opción para especificar un objeto en el que se adquirirá el bloqueo.

Ejemplo:

    Class Example {
    String test = "abc";
    // lock will be acquired on String  test object.
    synchronized (test) {
        // do something
    }

   lock will be acquired on Example Object
   public synchronized void testMethod() {
     // do some thing
   } 

   }
 2
Author: Srinu Yarru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-13 11:54:37

Sé que esta es una pregunta antigua, pero con mi rápida lectura de las respuestas aquí, realmente no vi a nadie mencionar que a veces un método synchronized puede ser el bloqueo incorrecto.
De Java Concurrency In Practice (pg. 72):

public class ListHelper<E> {
  public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...

public syncrhonized boolean putIfAbsent(E x) {
 boolean absent = !list.contains(x);
if(absent) {
 list.add(x);
}
return absent;
}

El código anterior tiene la apariencia de ser thread-safe. Sin embargo, en realidad no lo es. En este caso, el bloqueo se obtiene en la instancia de la clase. Sin embargo, es posible que la lista sea modificada por otro hilo no usando ese método. El enfoque correcto sería utilizar

public boolean putIfAbsent(E x) {
 synchronized(list) {
  boolean absent = !list.contains(x);
  if(absent) {
    list.add(x);
  }
  return absent;
}
}

El código anterior bloquearía todos los hilos tratando de modificar list de modificar la lista hasta que el bloque sincronizado se haya completado.

 2
Author: aarbor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-25 17:04:07

Como cuestión práctica, la ventaja de los métodos sincronizados sobre los bloques sincronizados es que son más resistentes a los idiotas; debido a que no puede elegir un objeto arbitrario para bloquear, no puede abusar de la sintaxis del método sincronizado para hacer cosas estúpidas como bloquear un literal de cadena o bloquear el contenido de un campo mutable que se cambia desde debajo de los hilos.

Por otro lado, con métodos sincronizados no puede proteger el bloqueo de ser adquirido por cualquier hilo que puede obtener una referencia al objeto.

Así que usar sincronizado como modificador en los métodos es mejor para proteger sus orkers de vaca de lastimarse a sí mismos, mientras que usar bloques sincronizados en conjunto con objetos privados de bloqueo final es mejor para proteger su propio código de los orkers de vaca.

 2
Author: Nathan Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 13:47:47

De un resumen de especificación de Java: http://www.cs.cornell.edu/andru/javaspec/17.doc.html

La instrucción sincronizada (§14.17) calcula una referencia a un objeto; a continuación, intenta realizar una acción de bloqueo en ese objeto y no continúe hasta que la acción de bloqueo se haya completado con éxito. ...

Un método sincronizado (§8.4.3.5) realiza automáticamente una acción de bloqueo cuando se invoca; su cuerpo no se ejecuta hasta que la acción de bloqueo completado con éxito. Si el método es un método de instancia , locks el bloqueo asociado con la instancia para la que se invocó (es decir, el objeto que se conocerá como este durante la ejecución de el cuerpo del método). Si el método es estático , bloquea el bloqueo asociado con el objeto de clase que representa la clase en que se define el método. ...

Basado en estas descripciones, yo diría que la mayoría de las respuestas anteriores son correctas, y un el método sincronizado puede ser particularmente útil para métodos estáticos, donde de lo contrario tendría que averiguar cómo obtener el objeto "Class" que representa la clase en la que se definió el método."

Editar: Originalmente pensé que estas eran citas de la especificación actual de Java. Aclaró que esta página es solo un resumen / explicación de la especificación

 1
Author: Josiah Yoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-19 13:15:08

TLDR; No usa el modificador synchronized ni la expresión synchronized(this){...} sino synchronized(myLock){...} donde myLock es un campo de instancia final que contiene un objeto privado.


La diferencia entre usar el modificador synchronized en la declaración del método y la expresión synchronized(..){ } en el cuerpo del método es la siguiente:

  • El modificador synchronized especificado en la firma del método
    1. es visible en el JavaDoc generado,
    2. es programáticamente determinable a través de reflexión al probar el modificador de un método para Modificador.SINCRONIZADO ,
    3. requiere menos tipificación y sangría en comparación con synchronized(this) { .... }, y
    4. (dependiendo de su IDE) es visible en el esquema de la clase y la finalización del código,
    5. utiliza el objeto this como lock cuando se declara en un método no estático o la clase de encierro cuando se declara en un método estático.
  • La expresión synchronized(...){...} le permite
    1. para sincronizar solo la ejecución de partes del cuerpo de un método,
    2. para ser utilizado dentro de un constructor o un bloque de inicialización (estático),
    3. para elegir el objeto lock que controla el acceso sincronizado.

Sin embargo, usar el modificador synchronized o synchronized(...) {...} con this como objeto de bloqueo (como en synchronized(this) {...}), tiene la misma desventaja. Ambos usan su propia instancia como el objeto de bloqueo para sincronizar. Esto es peligroso porque no solo el objeto en sí sino cualquier otro el objeto/código externo que contiene una referencia a ese objeto también puede usarlo como bloqueo de sincronización con efectos secundarios potencialmente graves (degradación del rendimiento y bloqueos ).

Por lo tanto, la mejor práctica es no usar el modificador synchronized ni la expresión synchronized(...) junto con this como objeto de bloqueo, sino un objeto de bloqueo privado para este objeto. Por ejemplo:

public class MyService {
    private final lock = new Object();

    public void doThis() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }

    public void doThat() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }
}

También puede usar varios objetos de bloqueo, pero debe tener especial cuidado para garantizar esto no da lugar a bloqueos cuando se utiliza anidado.

public class MyService {
    private final lock1 = new Object();
    private final lock2 = new Object();

    public void doThis() {
       synchronized(lock1) {
          synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThat() and doMore().
          }
    }

    public void doThat() {
       synchronized(lock1) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doMore() may execute concurrently
        }
    }

    public void doMore() {
       synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doThat() may execute concurrently
        }
    }
}
 1
Author: Sebastian Thomschke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-15 22:12:36

Sincronizando con hilos. 1) NUNCA use sincronizado (esto) en un hilo que no funciona. La sincronización con (esto) utiliza el hilo actual como objeto de hilo de bloqueo. Dado que cada hilo es independiente de otros hilos, no hay coordinación de sincronización. 2) Las pruebas de código muestran que en Java 1.6 en un Mac la sincronización del método no funciona. 3) sincronizado (lockObj) donde lockObj es un objeto común compartido de todos los hilos de sincronización en él funcionará. 4) ReenterantLock.bloqueo() y .unlock() trabajo. Vea tutoriales de Java para esto.

El siguiente código muestra estos puntos. También contiene el Vector thread-safe que sería sustituido por el ArrayList, para mostrar que muchos hilos que se agregan a un Vector no pierden ninguna información, mientras que lo mismo con un ArrayList puede perder información. 0) El código actual muestra la pérdida de información debido a las condiciones de la carrera A) Comente la actual etiquetada como Una línea, y descomente la línea A por encima de ella, luego ejecute, el método pierde datos pero no debería. B) Paso A inverso, descomento B y / / bloque final }. A continuación, ejecutar para ver los resultados sin pérdida de datos C) Comment out B, uncomment C. Run, see synchronizing on (this) loses data, as expected. No tienes tiempo para completar todas las variaciones, espero que esto ayude. Si la sincronización en (esto), o el método de sincronización funciona, por favor indique qué versión de Java y el sistema operativo que ha probado. Agradecer.

import java.util.*;

/** RaceCondition - Shows that when multiple threads compete for resources 
     thread one may grab the resource expecting to update a particular 
     area but is removed from the CPU before finishing.  Thread one still 
     points to that resource.  Then thread two grabs that resource and 
     completes the update.  Then thread one gets to complete the update, 
     which over writes thread two's work.
     DEMO:  1) Run as is - see missing counts from race condition, Run severa times, values change  
            2) Uncomment "synchronized(countLock){ }" - see counts work
            Synchronized creates a lock on that block of code, no other threads can 
            execute code within a block that another thread has a lock.
        3) Comment ArrayList, unComment Vector - See no loss in collection
            Vectors work like ArrayList, but Vectors are "Thread Safe"
         May use this code as long as attribution to the author remains intact.
     /mf
*/ 

public class RaceCondition {
    private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
//  private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)

    private String countLock="lock";    // Object use for locking the raceCount
    private int raceCount = 0;        // simple add 1 to this counter
    private int MAX = 10000;        // Do this 10,000 times
    private int NUM_THREADS = 100;    // Create 100 threads

    public static void main(String [] args) {
    new RaceCondition();
    }

    public RaceCondition() {
    ArrayList<Thread> arT = new ArrayList<Thread>();

    // Create thread objects, add them to an array list
    for( int i=0; i<NUM_THREADS; i++){
        Thread rt = new RaceThread( ); // i );
        arT.add( rt );
    }

    // Start all object at once.
    for( Thread rt : arT ){
        rt.start();
    }

    // Wait for all threads to finish before we can print totals created by threads
    for( int i=0; i<NUM_THREADS; i++){
        try { arT.get(i).join(); }
        catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
    }

    // All threads finished, print the summary information.
    // (Try to print this informaiton without the join loop above)
    System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
                MAX*NUM_THREADS, raceList.size(), raceCount );
    System.out.printf("Array lost %,d. Count lost %,d\n",
             MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
    }   // end RaceCondition constructor



    class RaceThread extends Thread {
    public void run() {
        for ( int i=0; i<MAX; i++){
        try {
            update( i );        
        }    // These  catches show when one thread steps on another's values
        catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
        catch( OutOfMemoryError oome ) { System.out.print("O"); }
        }
    }

    // so we don't lose counts, need to synchronize on some object, not primitive
    // Created "countLock" to show how this can work.
    // Comment out the synchronized and ending {, see that we lose counts.

//    public synchronized void update(int i){   // use A
    public void update(int i){                  // remove this when adding A
//      synchronized(countLock){            // or B
//      synchronized(this){             // or C
        raceCount = raceCount + 1;
        raceList.add( i );      // use Vector  
//          }           // end block for B or C
    }   // end update

    }   // end RaceThread inner class


} // end RaceCondition outter class
 -3
Author: user2277816,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-14 16:31:04