2009-09-15 5 views
6

En los últimos años he desarrollado UI principalmente en Eclipse, que es muy conservador en términos de acceso a subprocesos: cualquier intento de cambiar una propiedad en un widget de UI (por ejemplo, color, texto) desde fuera del subproceso de UI una excepción.¿Qué sucede cuando se viola la política de enhebrado de Swing?

Ahora estoy viendo un programa existente en Swing que tiene una ventana con una gran cantidad de artilugios personalizados. Hay hilos separados que ejecutan una función de mutación para cada uno de estos widgets, y la función de mutación lee el valor de algunas cosas (por ejemplo, colores y valores de las etiquetas) y escribe algunas (por ejemplo, cambia los colores de fondo). Tenga en cuenta que no hay ninguna pintura personalizada involucrada ni nada de eso, solo un montón de cambios en los sub widgets que contiene, que son en su mayoría JLabels.

En la actualidad, esto se ejecuta desde el hilo separado, no desde el hilo de evento Swing. Este hilo repasa todos los 400 widgets y llama al mutador en cada uno. Las actualizaciones parecen funcionar correctamente, pero la GUI no responde a la entrada del usuario.

Si tomo todo, que se ejecuta durante aproximadamente 0,4 mseg desde fuera del hilo Swing y envuelvo cada llamada a un mutador en un invokeLater o invokeAndWait, la interfaz de usuario es mucho más receptiva.

Lo que estoy tratando de entender es:

1) ¿Es legítimo veces para hacer todas estas llamadas desde fuera de la rosca oscilación?

2) ¿Cuál es el impacto en el hilo Swing y por qué la interfaz de usuario responde menos cuando lo llamo desde afuera?

Respuesta

3

De "Nada" a problemas intermitentes para "¡Todo se rompió, saca a todos a trabajar en la GUI!"

El efecto visual principal (más obvio) es que si sostienes el hilo de la GUI (como que alguien presiona un botón y duermes (5000) o algo así), tu GUI no se volverá a pintar. ¡No puede porque te estás agarrando al único hilo que te permite pasar! Esto hace que las personas piensen que Java es realmente lento. No está mal, pero es bastante fácil programar que mucha gente que no se molesta en investigar prácticas como esta ha producido productos de envío.

El siguiente gran problema es que cuando se dibuja la pantalla en otro hilo (como el que se pasa al principal), puede tener un comportamiento extraño. Swing ya es muy exigente con la forma en que renderizas tus cuadros, ¡saca los hilos como una variable!

Por último, rara vez (o a menudo si está llamando a un componente de giro en un lazo apretado en el hilo equivocado) puede obtener colisiones de hilo. Si eso ocurre, se puede lanzar (o no) una excepción y es probable que algo salga mal, pero puede que no sea obvio.

1

El problema básico es que los objetos que no son seguros para subprocesos se ejecutan de forma multiproceso. Incluso algo tan simple como leer HashMap se puede atrapar en un ciclo infinito. Debido a que AWT usa bloqueos (mal), también puede terminar con interbloqueos. Sin embargo, es probable que se salga con la suya, aunque es posible que una versión actualizada de Java ocasione problemas en algunas máquinas de los clientes.

(Por cierto:. Es de distribución de eventos hilo de AWT, no balancín)

1

Porque (1) como regla general cualquier cosa que actualiza los píxeles en la pantalla deben ser llamados desde el Event Dispatching Thread (EDT). Cuando algunas JVM pueden manejar actualizaciones desde fuera del EDT, de manera aceptable, nunca se debe confiar en que esto funcione, algunas máquinas y un aspecto y sensaciones diferentes no funcionarán de forma aceptable. El comportamiento no está definido, y esto podría explicar la falta de capacidad de respuesta que ha visto.

3

1) ¿A veces es legítimo hacer todas estas llamadas desde fuera del hilo Swing?

Existen algunas excepciones (establecer el valor de texto de un campo de texto, por ejemplo, realiza el proxing automático de EDT) - pero existen no situaciones en las que es mejor hacerlo. Si está realizando muchas actualizaciones, puede hacerlas todas en una sola llamada EDT (una sola llamada a invocarLater()) en lugar de llamadas individuales, pero incluso ese tipo de agrupamiento raramente ayuda. Largo y corto: realice operaciones en componentes Swing desde el EDT. Eso incluye lecturas y escrituras.

2) ¿Cuál es el impacto en el hilo Swing y por qué la interfaz de usuario responde menos cuando lo llamo desde afuera?

Bueno, el EDT es responsable de actualizar la GUI. Si llama desde afuera, no es "menos receptivo", es que las llamadas al sistema de bajo nivel real que actualizan la interfaz de usuario no se producen (en absoluto). Lo que probablemente esté sucediendo en su aplicación es que los desarrolladores originales están teniendo suerte y están cambiando el estado en el componente de swing sin crear una condición de carrera realmente desagradable. Luego, algún otro evento está causando un repintado en el EDT, lo que da como resultado la actualización del componente. Esto puede parecer una "falta de capacidad de respuesta", pero lo que realmente está sucediendo es una "falta de actualización de la pantalla".

El EDT es solo un hilo común, pero es un poco especial ya que se ejecuta en un circuito cerrado que procesa las señales relacionadas con la GUI (por ejemplo, comandos de dibujo). El hecho de publicar estos tipos de comandos en el EDT es muy, muy diferente de lo que típicamente consideramos como enhebrado de Java (se trata de enviar operaciones a una bomba de mensajes).

Largo y corto: todos los Javadocs que dicen 'solo interactúan con objetos Swing en el EDT' se escriben por un motivo. No te metas con eso. Si desea hacer un procesamiento en segundo plano, está bien, pero usted es responsable de volver a conectar la interacción con los componentes J * al EDT (más generalmente utilizando invokeLater()).

2
  1. Realmente no hay excepciones. Kevin es parcialmente correcto: JTextComponent.setText() se anuncia como seguro para subprocesos. Sin embargo, mirando el código 1.6, proporciona sincronización en el objeto del documento y no utiliza el EDT. Esto está bien, a menos que otro componente de swing (o algo que controle los componentes de swing) esté escuchando el objeto del documento. Ahórrese la molestia de preocuparse por eso, y solo use el EDT, como dice Kevin, realmente no hay situaciones (que yo sepa) para hacer lo contrario.

  2. Difícil de decir sin necesidad de indagar en el código; el comportamiento no está definido Si sus tareas en segundo plano duraron mucho tiempo (> unos segundos), vería el efecto contrario: usar EDT hará que la IU no responda mientras se ejecutan las tareas.

Afortunadamente, parece que hacerlo de la manera correcta funciona mejor para usted de todos modos. :)

Sun solía decir que era aceptable para utilizar otros hilos con componentes que no se han dado cuenta, pero más tarde se retractó:

Related stackoverflow question

Salida tutorial de la interfaz de usuario de Sun en swing y concurrencia (I 'd publicar el enlace, pero esta es mi primera respuesta en stackoverflow0.

Cuestiones relacionadas