java - example - thread safety php
¿Por qué esta clase no es segura para subprocesos? (7)
¿Alguien puede explicar por qué la clase anterior no es segura para subprocesos?
-
increment
es estático, la sincronización se realizará en la propia clase. -
decrement
no es estático, la sincronización se realizará en la instanciación del objeto, pero eso no asegura nada ya que elcount
es estático
Me gustaría agregar que para declarar un contador seguro para subprocesos, creo que la forma más simple es usar
AtomicInteger
lugar de un int primitivo.
Permíteme redirigirte a la información del paquete
java.util.concurrent.atomic
.
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?
-
decrement
es bloquear una cosa diferente paraincrement
modo que no impidan que se ejecuten entre sí. -
Llamar
decrement
en una instancia es bloquear una cosa diferente a llamardecrement
en otra instancia, pero están afectando lo mismo.
El primero significa que las llamadas superpuestas para
increment
y
decrement
podrían resultar en una cancelación (correcta), un incremento o una disminución.
El segundo significa que dos llamadas superpuestas para
decrement
en diferentes instancias podrían resultar en una doble disminución (correcta) o una sola disminución.
Como el método de
increment
es
static
, se sincronizará en el objeto de clase para
ThreadSafeClass
.
El método de
decrement
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 hilos diferentes pueden ejecutar los métodos al mismo tiempo.
Como las operaciones
++
y
--
no son atómicas, la clase no es segura para subprocesos.
Además, dado que el
count
es
static
, modificarlo desde
decrement
que es un método de
instancia
sincronizada, no es seguro ya que se puede invocar en diferentes instancias y modificar el
count
simultáneamente de esa manera.
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ático
decrement()
bloquea el monitor de objetos.
Para este ejemplo de código, existe una mejor solución sin el uso
synchronzed
palabras clave.
Tienes que usar
AtomicInteger
para lograr la seguridad de subprocesos.
Hilo seguro con
AtomicInteger
:
import java.util.concurrent.atomic.AtomicInteger;
class ThreadSafeClass extends Thread {
private static AtomicInteger count = new AtomicInteger(0);
public static void increment() {
count.incrementAndGet();
}
public static void decrement() {
count.decrementAndGet();
}
public static int value() {
return count.get();
}
}
Dado que hay dos métodos diferentes, uno es el nivel de instancia y otro es el nivel de clase, por lo que debe bloquear 2 objetos diferentes para que sea ThreadSafe
Las respuestas de otros son bastante buenas, explican la razón.
Solo agrego algo para resumir
synchronized
:
public class A {
public synchronized void fun1() {}
public synchronized void fun2() {}
public void fun3() {}
public static synchronized void fun4() {}
public static void fun5() {}
}
A a1 = new A();
synchronized
en
fun1
y
fun2
se sincroniza a nivel de objeto de instancia.
synchronized
en
fun4
se sincroniza a nivel de objeto de clase.
Lo que significa:
-
Cuando 2 hilos llaman a
a1.fun1()
al mismo tiempo, se bloqueará la última llamada. -
Cuando el subproceso 1 llame a
a1.fun1()
y el subproceso 2 llame aa1.fun2()
al mismo tiempo, se bloqueará la última llamada. -
Cuando el subproceso 1 llama a
a1.fun1()
y el subproceso 2 llama aa1.fun3()
al mismo tiempo, sin bloqueo, los 2 métodos se ejecutarán al mismo tiempo. -
Cuando el hilo 1 llame a
A.fun4()
, si otros hilos llaman aA.fun4()
oA.fun5()
al mismo tiempo, las últimas llamadas se bloquearán ya quesynchronized
enfun4
es el nivel de clase. -
Cuando el hilo 1 llama a
A.fun4()
, el hilo 2 llama aa1.fun1()
al mismo tiempo, sin bloqueo, los 2 métodos se ejecutarán al mismo tiempo.
Tiene dos métodos sincronizados, pero uno de ellos es estático y el otro no. Al acceder a un método sincronizado, basado en 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 Clase, 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 hilos que modifiquen el mismo objeto simultáneamente.