class ThreadSafeClass extends Thread
{
private static int count = 0;
public synchronized static void increment()
{
count++;
}
public synchronized void decrement()
{
count--;
}
}
¿Alguien puede explicar por qué la clase anterior no es segura para subprocesos?
java
multithreading
thread-safety
das kinder
fuente
fuente
increment
), sería seguro para subprocesos. O si usó algún objeto de bloqueo. Como dije, no sé sobre Java; mi comentario proviene del conocimiento de C #.synchronized
debe usarse solo en métodos estáticos. Entonces, en mi opinión, incluso si elimina elincrement
método, todavía no es seguro para subprocesos ya que dos instancias (que solo tienen acceso sincronizado a través de la misma instancia) pueden llamar al método simultáneamente.Respuestas:
Dado que el
increment
métodostatic
se sincronizará en el objeto de clase paraThreadSafeClass
. Eldecrement
método no es estático y se sincronizará en la instancia utilizada para llamarlo. Es decir, se sincronizarán en diferentes objetos y, por lo tanto, dos subprocesos diferentes pueden ejecutar los métodos al mismo tiempo. Dado que las operaciones++
y--
no son atómicas, la clase no es segura para subprocesos.Además, dado que
count
esstatic
, modificarlo a partir del método de instanciadecrement
sincronizada no es seguro, ya que se puede llamar en diferentes instancias y modificar simultáneamente de esa manera.count
fuente
count
es incorrectostatic
tener un método de instanciadecrement()
, incluso si no hay unstatic
increment()
método, ya que dos subprocesos pueden invocardecrement()
en diferentes instancias modificando el mismo contador al mismo tiempo.synchronized
bloques en general (incluso en todo el contenido del método) en lugar de usar el modificador en el método, es decir,synchronized(this) { ... }
ysynchronized(ThreadSafeClass.class) { ... }
.++
y--
no son atómicos, incluso encendidosvolatile int
.Synchronized
se ocupa del problema de lectura / actualización / escritura con++
/--
, pero lastatic
palabra clave es, bueno, la clave aquí. ¡Buena respuesta!synchronized
método de instancia. Simplemente no espere que "sincronizado" en el método de instancia proporcione protección para los datos estáticos. El único problema aquí es lo que dijo en su primer párrafo: los métodos utilizan diferentes bloqueos en un intento de proteger los mismos datos, y eso, por supuesto, no proporciona ninguna protección.Tiene dos métodos sincronizados, pero uno de ellos es estático y el otro no. Al acceder a un método sincronizado, según su tipo (estático o no estático), se bloqueará un objeto diferente. Para un método estático, se colocará un bloqueo en el objeto Class, mientras que para el bloque no estático, se colocará un bloqueo en la instancia de la clase que ejecuta el método. Debido a que tiene dos objetos bloqueados diferentes, puede tener dos subprocesos que modifiquen el mismo objeto simultáneamente.
fuente
increment
siendo estático, la sincronización se realizará en la propia clase.decrement
al no ser estático, la sincronización se realizará en la instanciación del objeto, pero eso no asegura nada ya quecount
es estático.Me gustaría agregar que para declarar un contador seguro para subprocesos, creo que la forma más simple es usar en
AtomicInteger
lugar de un int primitivo.Déjame redirigirte a la
java.util.concurrent.atomic
información del paquete.fuente
Las respuestas de otros son bastante buenas explicando la razón. Solo agrego algo para resumir
synchronized
:synchronized
enfun1
yfun2
se sincroniza a nivel de objeto de instancia.synchronized
onfun4
se sincroniza a nivel de objeto de clase. Lo que significa:a1.fun1()
al mismo tiempo, se bloqueará la última llamada.a1.fun1()
y el hilo 2 llamaa1.fun2()
al mismo tiempo, la última llamada será bloqueada.a1.fun1()
y el hilo 2 llamaa1.fun3()
al mismo tiempo, sin bloqueo, los 2 métodos se ejecutarán al mismo tiempo.A.fun4()
, si llaman otros hilosA.fun4()
oA.fun5()
al mismo tiempo, estas últimas llamadas serán bloqueados desdesynchronized
elfun4
es el nivel de clase.A.fun4()
, el hilo 2 llamaa1.fun1()
al mismo tiempo, sin bloqueo, los 2 métodos se ejecutarán al mismo tiempo.fuente
decrement
está bloqueando algo diferente paraincrement
que no se impidan que se ejecuten.decrement
a una instancia es bloquear una cosa diferente a llamardecrement
a otra instancia, pero están afectando lo mismo.La primera significa que las llamadas superpuestas a
increment
ydecrement
podrían resultar en una cancelación (correcta), un incremento o una disminución.El segundo significa que dos llamadas superpuestas a
decrement
en diferentes instancias podrían resultar en una disminución doble (correcta) o una disminución simple.fuente
Dado que hay dos métodos diferentes, uno es el nivel de instancia y el otro es el nivel de clase, por lo que debe bloquear 2 objetos diferentes para que sea ThreadSafe
fuente
Como se explica en otras respuestas, su código no es seguro para subprocesos, ya que el método estático
increment()
bloquea el monitor de clase y el método no estáticodecrement()
bloquea el monitor de objeto.Para este ejemplo de código, existe una mejor solución sin el
synchronzed
uso de palabras clave. Tienes que usar AtomicInteger para lograr la seguridad de Thread.Uso seguro para subprocesos
AtomicInteger
:fuente