Ernst Baumann
2009-02-26 20:19:46 UTC
Hallo allerseits,
1)
a)
In dem einfachen Demo-Programm unten werden verzögert Kreise auf dem
Bildschirm dargestellt. Das Programm funktioniert zwar problemlos,
aber ich verstehe nicht ganz genau, warum es problemlos funktioniert.
Mit invokeLater(...) werden jeweils die sich in run(..) befindlichen
Anweisungen in die Warteschlange des EDT gestellt.
Da der EDT ein Thread ist, gibt es innerhalb dieses Threads keine
parallelen, konkurrierenden Zugriffe auf die gleichen Variablen.
Deshalb gibt es keine Probleme, wenn es innerhalb dieses EDT
Lesezugriffe (wie z.B. beim Zeichnen eines Kreises auf die Koordinaten
) und Schreibzugriffe (wie z.B. die Koordinaten eines Kreises setzen)
auf die _gleiche_ Variable gibt.
b)
Neben diesem EDT gibt es den Main-Thread (in dem die Methode main
abläuft)
In diesem gibt es u.a. die folgenden Anweisungen:
stelle = 1;
Diagramm diagramm = new Diagramm(550, 550);
JFrame f = new JFrame();
f.setSize(550,550);
f.getContentPane().add(diagramm);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
Das heißt im Main-Thread gibt es u.a. auf die folgenden Variablen
Schreibzugriffe:
stelle
diagramm
f
Aber im EDT wird auf die Variable
stelle
und indirekt auf diagramm (über das Attribut myimg in diagramm)
und indirekt auf f über f.getContentPane().add(diagramm);
zugegriffen (also auf die gleichen Variablen wie im Main-Thread).
Man hat also _konkurrierende_ Zugriffe in 2 verschiedenen Threads auf
die _gleichen_ Variablen.
Warum gibt es keine Probleme (die Zugriffe werden ja nicht durch
synchronized legal geregelt)?
c)
Meine Erklärung:
Vielleicht geschieht der Zugriff auf diese Variablen im EDT zeitlich
_nach_ dem Main-Thread:
c1)
Die Anweisung f.setVisible(true) im Main-Thread löst den Aufruf von
repaint() aus.
repaint stellt die entsprechenden Anweisungen in den EDT und fordert
_dann_ den EDT-Thread an
c2)
Die Anweisung invokeLater(...) stellt die Anweisungen in run(...) in
den EDT und fordert _dann_ den EDT-Thread an.
Aber wann der EDT ausgeführt wird, bestimmt doch das Betriebssystem.
Deswegen ist mir dies nicht richtig klar!
Sind meine Erklärungn richtig, bzw. was stimmt nicht und muss ergänzt
werden?
2)
a)
Mir wurde gesagt:
Von außerhalb des EDT soll nicht auf bereits realisierte
Swing/AWT-Objekte zugegriffen werden.
Das wird doch aber bei meinem Programm im Main Thread gemacht, z.B.
werden auf die folgenden Variablen (Swing/AWT-Objekte) zugegriffen:
diagramm
f
b)
Die Aussage bei 2a) müsste eigentlich noch verschärft werden:
Man darf eigentlich gar nicht von außerhalb, also von einem anderen
Thread auf den EDT zugreifen, außer man regelt das mit synchronized.
Ist das richtig?
mfg
Ernst
----------------------------------------------------------------
package verzoegertzeichnen3;
import java.awt.*;
import javax.swing.*;
public class MainVerzoegertZeichnen3 {
public static void main(String[] args){
int stelle;
stelle = 1;
Diagramm diagramm = new Diagramm(550, 550);
JFrame f = new JFrame();
f.setSize(550,550);
f.getContentPane().add(diagramm);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
while(stelle<=10){
System.out.println("stelle in main="+stelle);
try{
Thread.sleep(100);
}
catch(Exception e){}
stelle=stelle+1;
// ohne anonyme Klasse
MyRunnable myR = new MyRunnable(diagramm, stelle);
javax.swing.SwingUtilities.invokeLater(myR);
}
}
}
class Diagramm extends JPanel{
private int xpAnz;
private int ypAnz;
private int ort;
private Image myimg;
private Graphics myg;
private int sx;
private int sy;
public Diagramm(int xpAnz, int ypAnz){
ort=0;
this.xpAnz=xpAnz;
this.ypAnz=ypAnz;
myimg=null;
}
public void setOrt(int pOrt){
ort=pOrt;
}
// ist im EDT (siehe Methode void run)
public void male(){
if(myimg==null){
sx = this.getSize().width;
System.out.println("sx="+sx);
System.out.println("sy="+sy);
sy = this.getSize().height;
myimg = createImage(sx, sy);
myg = myimg.getGraphics();
}
// Schreibzugriff auf myimg
myg.setColor(Color.red);
myg.drawOval(ort*20 , ort*20, 20, 20);
}
// ist im EDT
public void paintComponent(Graphics g){
System.out.println("paintComponent");
// Lesezugriff auf myimg
g.drawImage(myimg,0,0,null);
}
}
class MyRunnable implements Runnable{
private Diagramm diagramm;
private int ort;
public void run(){
// ist im EDT
// Schreibzugriff auf ort
diagramm.setOrt(ort);
// Schreibzugriff auf mying
diagramm.male();
// Lesezugriff auf mying in paintComponent
diagramm.repaint();
}
public MyRunnable(Diagramm pDiagramm, int pOrt){
diagramm = pDiagramm;
ort = pOrt;
}
}
----------------------------------------------------------------
1)
a)
In dem einfachen Demo-Programm unten werden verzögert Kreise auf dem
Bildschirm dargestellt. Das Programm funktioniert zwar problemlos,
aber ich verstehe nicht ganz genau, warum es problemlos funktioniert.
Mit invokeLater(...) werden jeweils die sich in run(..) befindlichen
Anweisungen in die Warteschlange des EDT gestellt.
Da der EDT ein Thread ist, gibt es innerhalb dieses Threads keine
parallelen, konkurrierenden Zugriffe auf die gleichen Variablen.
Deshalb gibt es keine Probleme, wenn es innerhalb dieses EDT
Lesezugriffe (wie z.B. beim Zeichnen eines Kreises auf die Koordinaten
) und Schreibzugriffe (wie z.B. die Koordinaten eines Kreises setzen)
auf die _gleiche_ Variable gibt.
b)
Neben diesem EDT gibt es den Main-Thread (in dem die Methode main
abläuft)
In diesem gibt es u.a. die folgenden Anweisungen:
stelle = 1;
Diagramm diagramm = new Diagramm(550, 550);
JFrame f = new JFrame();
f.setSize(550,550);
f.getContentPane().add(diagramm);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
Das heißt im Main-Thread gibt es u.a. auf die folgenden Variablen
Schreibzugriffe:
stelle
diagramm
f
Aber im EDT wird auf die Variable
stelle
und indirekt auf diagramm (über das Attribut myimg in diagramm)
und indirekt auf f über f.getContentPane().add(diagramm);
zugegriffen (also auf die gleichen Variablen wie im Main-Thread).
Man hat also _konkurrierende_ Zugriffe in 2 verschiedenen Threads auf
die _gleichen_ Variablen.
Warum gibt es keine Probleme (die Zugriffe werden ja nicht durch
synchronized legal geregelt)?
c)
Meine Erklärung:
Vielleicht geschieht der Zugriff auf diese Variablen im EDT zeitlich
_nach_ dem Main-Thread:
c1)
Die Anweisung f.setVisible(true) im Main-Thread löst den Aufruf von
repaint() aus.
repaint stellt die entsprechenden Anweisungen in den EDT und fordert
_dann_ den EDT-Thread an
c2)
Die Anweisung invokeLater(...) stellt die Anweisungen in run(...) in
den EDT und fordert _dann_ den EDT-Thread an.
Aber wann der EDT ausgeführt wird, bestimmt doch das Betriebssystem.
Deswegen ist mir dies nicht richtig klar!
Sind meine Erklärungn richtig, bzw. was stimmt nicht und muss ergänzt
werden?
2)
a)
Mir wurde gesagt:
Von außerhalb des EDT soll nicht auf bereits realisierte
Swing/AWT-Objekte zugegriffen werden.
Das wird doch aber bei meinem Programm im Main Thread gemacht, z.B.
werden auf die folgenden Variablen (Swing/AWT-Objekte) zugegriffen:
diagramm
f
b)
Die Aussage bei 2a) müsste eigentlich noch verschärft werden:
Man darf eigentlich gar nicht von außerhalb, also von einem anderen
Thread auf den EDT zugreifen, außer man regelt das mit synchronized.
Ist das richtig?
mfg
Ernst
----------------------------------------------------------------
package verzoegertzeichnen3;
import java.awt.*;
import javax.swing.*;
public class MainVerzoegertZeichnen3 {
public static void main(String[] args){
int stelle;
stelle = 1;
Diagramm diagramm = new Diagramm(550, 550);
JFrame f = new JFrame();
f.setSize(550,550);
f.getContentPane().add(diagramm);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
while(stelle<=10){
System.out.println("stelle in main="+stelle);
try{
Thread.sleep(100);
}
catch(Exception e){}
stelle=stelle+1;
// ohne anonyme Klasse
MyRunnable myR = new MyRunnable(diagramm, stelle);
javax.swing.SwingUtilities.invokeLater(myR);
}
}
}
class Diagramm extends JPanel{
private int xpAnz;
private int ypAnz;
private int ort;
private Image myimg;
private Graphics myg;
private int sx;
private int sy;
public Diagramm(int xpAnz, int ypAnz){
ort=0;
this.xpAnz=xpAnz;
this.ypAnz=ypAnz;
myimg=null;
}
public void setOrt(int pOrt){
ort=pOrt;
}
// ist im EDT (siehe Methode void run)
public void male(){
if(myimg==null){
sx = this.getSize().width;
System.out.println("sx="+sx);
System.out.println("sy="+sy);
sy = this.getSize().height;
myimg = createImage(sx, sy);
myg = myimg.getGraphics();
}
// Schreibzugriff auf myimg
myg.setColor(Color.red);
myg.drawOval(ort*20 , ort*20, 20, 20);
}
// ist im EDT
public void paintComponent(Graphics g){
System.out.println("paintComponent");
// Lesezugriff auf myimg
g.drawImage(myimg,0,0,null);
}
}
class MyRunnable implements Runnable{
private Diagramm diagramm;
private int ort;
public void run(){
// ist im EDT
// Schreibzugriff auf ort
diagramm.setOrt(ort);
// Schreibzugriff auf mying
diagramm.male();
// Lesezugriff auf mying in paintComponent
diagramm.repaint();
}
public MyRunnable(Diagramm pDiagramm, int pOrt){
diagramm = pDiagramm;
ort = pOrt;
}
}
----------------------------------------------------------------