¿Son seguros los hilos estáticos no sincronizados si no modifican las variables de clase estática?

145

Me preguntaba si tiene un método estático que no esté sincronizado, pero que no modifique ninguna variable estática, ¿es seguro para subprocesos? ¿Qué pasa si el método crea variables locales dentro de él? Por ejemplo, ¿el siguiente código es seguro para subprocesos?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

Entonces, si tengo dos hilos que llaman a este método de forma continua y simultánea, uno con perros (diga "gran danés" y "perro toro") y el otro con gatos (diga "persa" y "siamés") alguna vez tendré gatos y perros en la misma matriz? ¿O los gatos y los perros nunca estarán dentro de la misma invocación del método al mismo tiempo?

Trineo
fuente
otro hilo sobre este tema: stackoverflow.com/questions/8015797/…
象 嘉 道
2
Esa es una pregunta diferente, esto es si la invocación de métodos estáticos es segura para subprocesos, no si las matrices lo son.
Trineo

Respuestas:

212

Este método es 100% seguro para subprocesos, lo sería incluso si no lo fuera static. El problema con la seguridad de subprocesos surge cuando necesita compartir datos entre subprocesos: debe cuidar la atomicidad, la visibilidad, etc.

Este método solo funciona con parámetros, que residen en la pila y referencias a objetos inmutables en el montón. Stack es inherentemente local al hilo , por lo que nunca se comparte información.

Los objetos inmutables ( Stringen este caso) también son seguros para subprocesos porque una vez creados no se pueden cambiar y todos los subprocesos ven el mismo valor. Por otro lado, si el método aceptara (mutable) Date, podría haber tenido un problema. Dos hilos pueden modificar simultáneamente esa misma instancia de objeto, causando condiciones de carrera y problemas de visibilidad.

Tomasz Nurkiewicz
fuente
44
Respuesta correcta. Las variables de nivel de método se replican en cada pila de ejecución de subprocesos.
Sid
técnicamente, el método debe estar en línea y los parámetros serán registros de CPU. Sin embargo, la respuesta es correcta
bestsss
43
La pila es, por supuesto, local para el hilo actual, pero puede tener referencias a objetos compartidos en esa pila. Esto no es un problema en el ejemplo ya que las cadenas son inmutables, pero un método que modifica un parámetro pasado puede tener problemas de seguridad de subprocesos si este objeto pasado es accesible desde múltiples subprocesos.
Jörn Horstmann
1
Como @TomaszNurkiewicz mencionó, si pasamos una referencia de objeto mutable, podemos entrar en condiciones de carrera. ¿Esto es cierto incluso si el método no cambia el objeto de ninguna manera? Quiero decir, ¿seguirá siendo clasificado como una condición de carrera porque el objeto era mutable? ¿Y si agregamos la palabra clave final a los parámetros?
Rafay
¿Qué pasa si paso el objeto de clase en el método? ¿Lo varaible en la pila o el montón?
grep
28

Un método solo puede ser inseguro para subprocesos cuando cambia algún estado compartido. Si es estático o no es irrelevante.

Konrad Garus
fuente
3
@Konrad_Garus La pregunta aquí era si las variables locales constituyen un estado compartido o no, o si la pila de un método estático era por hilo o compartida.
Trineo
"Un método solo puede ser inseguro para subprocesos cuando cambia algún estado compartido". No, también puede ser inseguro en el hilo si simplemente accede al estado compartido sin cambiarlo. El acceso no sincronizado a un objeto mutable puede acceder a un estado incoherente si el objeto está siendo mutado por otro hilo, incluso si el otro hilo está sincronizado correctamente. Ambos hilos necesitan una sincronización adecuada para mantener la seguridad del hilo.
Warren Dew
12

La función es perfectamente segura para hilos.

Si lo piensas ... asume lo que sucedería si esto fuera diferente. Todas las funciones habituales tendrían problemas de subprocesos si no estuvieran sincronizadas, por lo que todas las funciones de API en el JDK tendrían que estar sincronizadas, ya que potencialmente podrían ser llamadas por múltiples subprocesos. Y dado que la mayor parte del tiempo la aplicación usa alguna API, las aplicaciones multiproceso serían efectivamente imposibles.

Esto es demasiado ridículo para pensarlo, así que solo para usted: los métodos no son seguros si hay una razón clara por la que podría haber problemas. Intente siempre pensar en qué pasaría si hubiera varios subprocesos en mi función, y qué pasaría si tuviera un depurador de pasos y avanzara un paso tras otro el primero ... luego el segundo hilo ... tal vez el segundo nuevamente ... habría problemas? Si encuentra uno, no es seguro para subprocesos.

Tenga en cuenta también que la mayoría de las clases de Java 1.5 Collection no son seguras para subprocesos, excepto aquellas donde se indica, como ConcurrentHashMap.

Y si realmente quieres sumergirte en esto, mira de cerca la palabra clave volátil y TODOS sus efectos secundarios. Eche un vistazo a las clases Semaphore () y Lock (), y sus amigos en java.util.Concurrent. Lea todos los documentos de API alrededor de las clases. Vale la pena aprender y satisfacer también.

Perdón por esta respuesta demasiado elaborada.

Daniel
fuente
2
"Si lo piensa ... suponga lo que sucedería si esto fuera diferente. Todas las funciones habituales tendrían problemas de subprocesos si no estuvieran sincronizadas, por lo que todas las funciones API en el JDK tendrían que estar sincronizadas, ya que potencialmente podrían ser llamadas por múltiples hilos." ¡Buen punto!
Trineo
1

Use la staticpalabra clave con métodos estáticos sincronizados para modificar datos estáticos compartidos entre subprocesos. Con la staticpalabra clave, todos los hilos creados competirán por una única versión del método.

El uso de la volatilepalabra clave junto con los métodos de instancia sincronizada garantizará que cada subproceso tenga su propia copia de los datos compartidos y que no se filtre lectura / escritura entre los subprocesos.

Clinton
fuente
0

Los objetos de cadena que son inmutables es otra razón para el escenario anterior seguro para subprocesos. En cambio, si se utilizan objetos mutables (por ejemplo, makeMutableArray ...), entonces seguramente se romperá la seguridad de subprocesos.

duro
fuente
La pregunta era si una llamada al método estático vería alguna vez los argumentos de otra llamada al mismo método desde otro hilo. La respuesta es un rotundo "¡no!". Sabía esto, pero quería demostrarle a los dudosos compañeros de trabajo.
Trineo
¿Por qué se rechazó esta respuesta? El punto, no contribuido por las otras respuestas, es que la mutabilidad puede estar entrante o saliente. Si devuelve un mutable, entonces no es seguro. La pregunta no plantea su pregunta tan estrechamente como sugiere el comentario; La pregunta extendida después de la muestra de código podría haberse expresado en código, tal vez como una prueba unitaria. Pero simpatizo con tratar de convencer a los compañeros de trabajo. "No me creen, ni a mi código de prueba, ni a Josh Bloch, pero tal vez acepten una respuesta en SO".
som-snytt