2011-10-30 11 views
6

Mi proyecto java appengine no mantiene ningún estado entre solicitudes, excepto para los siguientes usos de Memcache:Lista de verificación para java thread-safe en appengine

  • Objectify utiliza Memcache para almacenar en caché del almacén de datos se
  • utilizo Memcache como una forma de tareas de limpieza por lotes después de varias solicitudes (por ejemplo, if (the memcache doesn't think a cleanup task is already running) schedule another cleanup task).

que no tienen referencias globales/estáticas a todos los objetos, excepto:

  • El usuario autenticado actual se mantiene en un objeto static ThreadLocal<User>. Esto significa que cada solicitud tendrá su propia copia de un Usuario, ¿verdad?
  • Tengo una clase que maneja toda la manipulación de datos, y una instancia se mantiene como una especie de variable global en un objeto static DataCoordinator.

¿Qué debo tener en cuenta para hacer que mi código sea seguro para subprocesos? ¿Debo arrojar una palabra clave synchronized en cada declaración de método en mi implementación DataCoordinator, ya que varios subprocesos podrían acceder a ella? ¿Es cierto que el objeto ThreadLocal<User> siempre creará un objeto User por separado para cada subproceso, de modo que cada solicitud se autenticará por separado?

Soy un novato total para el pensamiento seguro de subprocesos. ¿Qué debería leer?

Gracias por cualquier ayuda, y disculpe por la falta de especificidad.

+0

¿Tiene alguna singlton clases, en las que siempre se obtiene una referencia a la misma instancia a través de un .getInstance()? Si es así, múltiples solicitudes paralelas ejecutadas en diferentes subprocesos dentro de la misma VM/instancia podrían obtener una referencia al mismo objeto ... y luego clasificarlas en su uso o modificación de variables de instancia. –

Respuesta

7

Lo primero que debes tener en cuenta es que el motor de aplicaciones puede replicar tu aplicación en varios servidores. Eso significa que sus variables estáticas serán únicas solo en un servidor. Por lo tanto, su DataCoordinator coordinará solo el acceso a los datos en un único servidor. Entonces, si necesita datos comunes para todos los servidores que ejecutan su aplicación, siempre debe usar el almacén de datos para ese (o el mecanismo de sesión HTTP gae en algunos casos).

Con respecto a la seguridad de subprocesos de DataCoordinator: Solo necesita sincronizar los métodos de este coordinador si estos métodos no se implementan de manera segura para subprocesos. Por ejemplo, no necesita sincronizar ningún método que no acceda a ninguna instancia/datos estáticos, sino que simplemente obtenga datos del almacén de datos. Si los métodos acceden a la instancia común/datos estáticos que son mutables (también se escribe al mismo tiempo), en la mayoría de los casos se puede sincronizar en un monitor especial para los datos a los que se accede, en lugar de sincronizar en todo el coordinador.

Con respecto a su ThreadLocal utilizado para almacenar el token de autenticación: Lo hago (hago eso por ejemplo para autenticación de usuario en gae para solicitudes de fábrica de solicitud GWT) y sí, cada hilo tendrá su propio valor variable siempre que establezca por ese hilo. Lo que significa que es mejor asegurarse de que la variable esté configurada para cada subproceso y es aconsejable usar un bloque try - finally después de configurarlo que eventualmente elimine los datos de autenticación después de su uso. ¿Por qué? Lo peor que podría pasar sería que un subproceso que pertenece a la solicitud del usuario B todavía tenga un token de autenticación del usuario A. Esto se debe a que los subprocesos utilizados en el servidor de aplicaciones generalmente se agrupan entre las solicitudes en lugar de compilarse y recrearse.

No puedo decir nada sobre Memcache porque no lo he usado.

Generalmente, debe tener en cuenta que el servidor puede gestionar cualquier solicitud web (servlet/JSP/...).Por lo tanto, todos los recursos compartidos mutables a los que acceden estos hilos deben estar sincronizados o implementados de manera segura.

Tal vez http://download.oracle.com/javase/tutorial/essential/concurrency/ es un buen punto de partida para leer en él.

+0

No necesito que la cadena de datos sea la misma para todos los hilos, solo lo necesito para no estropear nada cuando dos subprocesos en competencia acceden a él. Gracias por la respuesta. Veré este tutorial. –

3

Si tiene clases singleton, solo una instancia será creada/usada por su código por VM/instancia creada.

referencia a la presente Singleton se pueden recuperar a partir de:
- dos peticiones secuenciales hicieron uno tras otro que se sirve de la misma instancia (depende de la configuración de cuánto tiempo permanecen alrededor, o si una instancia reservada se está ejecutando)
- dos solicitudes paralelas que se ejecutan en subprocesos separados en la misma instancia SI tiene establecido el enhebrado en verdadero.

He escrito y probado el código para confirmarlo, y desplegado y probado. Si el código en una solicitud utiliza el singleton para modificar una de sus variables miembro, entonces se modifica para la otra solicitud que se ejecuta en paralelo.

Todo muy lógico, una vez que descubra la vida útil de una VM y cuántos hilos (solo 1, o muchos) se utilizan para atender solicitudes entrantes.

Además, las variables del sistema se pueden modificar en el código en una solicitud y leer en otra ... una segunda forma en que dos solicitudes/hilos paralelos pueden interactuar.

ver más detalles sobre esto en mi blog el multi-threading en GAE/J aquí:
http://devcon5.blogspot.com/2012/09/threadsafe-in-appengine-gaej.html

Cuestiones relacionadas