Foro sobre Java SE > Repaint() Tread Safe en swing
Posiblemente este artículo aclare algo la cuestión sobre AWT y Thread-safe.
http://c2.com/cgi/wiki?TheGuiThreadIsTheMainThread
Lo cierto es que no conozco ninguna afirmación oficial por parte de Oracle (ni antes SUN), que asegure que AWT es thread-safe. Más bien afirman que se debe suponer que no lo es, a menos que se diga explícitamente que sí para algunos métodos, como invalidate().
Respecto a ese método en particular, todo el bloque de código anterior a la delegación al parent, accede a propiedades de la clase, sin sincronizar.
Bueno, no se Oracle pero por ejemplo los ingenieros del equipo de desarrollo de Swing si que lo afirman:
https://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
No se porque algo tiene que estar sincronizado para que sea thread safe. No son sinonimos. La clase String es thread safe al ser inmutable, pero no esta sincronizada.
En este caso el codigo se asegura de que la llamadas al repaint pasen siempre por el edt y no invoquen dirtamente desde otro thread.
Un saludo
Me equivoque con el articulo, que lo que afirma es que repaint es thread safe.
Es cierto que el que AWT sea thread safe no es claro y de hecho no lo es en absoluto. De hecho despues de leer este articulo estoy seguro de que no lo es:
http://docs.oracle.com/javase/8/docs/technotes/guides/tsgdesktop/awt.html
Un saludo
"No se porque algo tiene que estar sincronizado para que sea thread safe. No son sinonimos. La clase String es thread safe al ser inmutable, pero no esta sincronizada."
Es que la clase Component no es inmutable como String.
Si una tarea modifica sus propiedades, mientra otra hace un repaint(), no se puede asegurar la consistencia del resultado de ese repaint().
Yo no digo que Component sea inmutable ni que sea thread safe.
Lo que digo es que el metodo repaint() esta programado para que no se vea afectado por condiciones de carrera. Para conseguir esto no hace falta siempre sincronizarlo. En este caso lo que hace es redigir siempre el repintado a la cola del EDT.
P.D: esta claro que con lo cabezones que somos los asturianos no vamos a dar el brazo a torcer ;-)
Un saludo
Hablando de "torcer brazos"... :D
if (parent != null) {
if (x < 0) {
width += x;
x = 0;
}
if (y < 0) {
height += y;
y = 0;
}
int pwidth = (width > this.width) ? this.width : width;
int pheight = (height > this.height) ? this.height : height;
if (pwidth <= 0 || pheight <= 0) {
return;
}
int px = this.x + x;
int py = this.y + y;
te doy la razón... a partir de esta línea; para las anteriores, ni hablar :)
parent.repaint(tm, px, py, pwidth, pheight);
Ese codigo en una aplicacion Swing no se ejecuta nunca, ya que el repaint que se lanza es el de JComponent y no el de Component.
El flujo en una llamada repaint() seria:
Component::repaint()---->JComponent::repaint(0, 0, 0, width, height)-->RepaintMananger::addDirtyRegion.....
Lamento no estar de acuerdo. Sigue un test.
Línea 3304 de Component:
public void repaint() {
repaint(0, 0, 0, width, height);
}
Ese repaint(0, 0, 0, width, height) local es exactamente el mismo código que he publicado hasta ahora, y que comienza en la línea 3373 de Component.
La llamada al repaint que comentas es la que he resaltado en el mensaje anterior.
Esos números de líneas corresponden a JavaSE 1.8
public class NewJFrame extends javax.swing.JFrame {
/** Creates new form NewJFrame */
public NewJFrame() {
initComponents();
repaint(); // línea 3304 de Component
}
/** This method is called from within the constructor to
initialize the form.
WARNING: Do NOT modify this code. The content of this method is
always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
/**
@param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
Por ponerlo más claro.
El orden jerárquico de las clases es: Component <- Container <- JComponent
Ese parent de la línea resaltada es una instancia de Container dentro de Component.
La delegación que comentas se produce precisamente en esa línea
Nop
Te lo voy a poner muy fácil. Lo vas a comprobar tú mismo. Depura tu programa de ejemplo, poniendo un punto de interrupción en la primera línea del método repaint(long tm, int x, int y, int width, int height) de la clase Component. En ese código que dices que no es thread safe.
Sorpresa! No se ejecuta nunca!
JFrame hereda de Component así como de JComponent. Cuando lanza repaint(), llama al método de Component, ya que en JComponent no existe, pero cuando éste a su vez llama al repaint(long tm, int x, int y, int width, int height), el método que se ejecuta no es el "local" como tu dices, sino el de JComponent. Tu sabes perfectamente porqué, así que no me voy a enrollar.
Un saludo
¡Totalmente cierto!
Entre que no usan la anotación @Override y que los hints de NetBeans, con tantas clases involucradas y tan extensas, tardan un verano en aparecer...
Buenas,
Traigo al foro el tema que estaba discutiendo con choces, ya que en la noticia cada vez que publico el comentario necesita ser aprobado y eso lleva mucho tiempo...
@choces
No veo porque el hecho de que el EDT este implementado en la parte de AWT hace que este no sea thread safe.
AWT es thread safe porque sus componentes pueden ser invocados desde otros threads diferentes al EDT, algo que no se puede hacer en swing. Esto es asi porque AWT delega en el sistema de ventanas del SO sobre el que se ejecuta.
Respecto al metodo repaint sin metodos, si te fijas en su implementacion en AWT veras que delega por polimorfismo. Cuando se ejecuta en swing, llama a su repaint con parametros de JComponent que utiliza a su vez el RepaintManager que se encarga de poner la orden de paint() en la cola del EDT.
public void repaint() {
repaint(0, 0, 0, width, height);
}
Un saludo