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 #.synchronizeddebe usarse solo en métodos estáticos. Entonces, en mi opinión, incluso si elimina elincrementmé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
incrementmétodostaticse sincronizará en el objeto de clase paraThreadSafeClass. Eldecrementmé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
countesstatic, modificarlo a partir del método de instanciadecrementsincronizada no es seguro, ya que se puede llamar en diferentes instancias y modificar simultáneamente de esa manera.countfuente
countes incorrectostatictener un método de instanciadecrement(), incluso si no hay unstaticincrement()método, ya que dos subprocesos pueden invocardecrement()en diferentes instancias modificando el mismo contador al mismo tiempo.synchronizedbloques 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.Synchronizedse ocupa del problema de lectura / actualización / escritura con++/--, pero lastaticpalabra clave es, bueno, la clave aquí. ¡Buena respuesta!synchronizedmé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
incrementsiendo estático, la sincronización se realizará en la propia clase.decremental no ser estático, la sincronización se realizará en la instanciación del objeto, pero eso no asegura nada ya quecountes estático.Me gustaría agregar que para declarar un contador seguro para subprocesos, creo que la forma más simple es usar en
AtomicIntegerlugar de un int primitivo.Déjame redirigirte a la
java.util.concurrent.atomicinformación del paquete.fuente
Las respuestas de otros son bastante buenas explicando la razón. Solo agrego algo para resumir
synchronized:synchronizedenfun1yfun2se sincroniza a nivel de objeto de instancia.synchronizedonfun4se 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 desdesynchronizedelfun4es 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
decrementestá bloqueando algo diferente paraincrementque no se impidan que se ejecuten.decrementa una instancia es bloquear una cosa diferente a llamardecrementa otra instancia, pero están afectando lo mismo.La primera significa que las llamadas superpuestas a
incrementydecrementpodrían resultar en una cancelación (correcta), un incremento o una disminución.El segundo significa que dos llamadas superpuestas a
decrementen 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
synchronzeduso de palabras clave. Tienes que usar AtomicInteger para lograr la seguridad de Thread.Uso seguro para subprocesos
AtomicInteger:fuente