JVM Bug oder Denkfehler?

Hallo,

ich habe gerade an einem kleinen Programm geschrieben. Es geht dabei um ein Frame, welches verädert (vergößert, um genau zu sein) werden soll, sobald es sichtbar ist. Dazu wird einfach ein Thread gestartet, der ununterbrochen überprüt, ob das Frame schon sichtbar ist. Hier erstmal der vereinfachte Code:
public class Test {

static final JFrame frame;

static {
frame = new JFrame(„Hallo“);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
setSize(300, 200);
}

public static void main(String[] args) {
frame.setVisible(true);
}

private static void setSize(final int width, final int height) {
if (frame.isVisible()) {
frame.setSize(width, height);
frame.setLocationRelativeTo(null);
} else {
new Thread(){
public void run() {
// Hier ist jetzt die Abfrage…
while (!frame.isVisible()) {
// Leere Schleife, die verlassen werden soll,
// sobald das Frame sichtbar ist.
}
setSize(width, height);
}
}.start();
}
}
}
Der Code funktioniert jedoch nicht, das Frame hat die Größe 0x0. Wenn ich jetzt aber in die Schleife die Funktion System.out.println();schribe, dann funktioniert es einwandfrei! Hab ich da jetzt echt einen verrückten Denkfehler oder liegt das an Java? Vielleicht habt ihr ja eine Idee…

Grüße Keks

Hallo!
War das nicht auch unter Java so, dass der Zugriff auf UI Elemente ausschließlich aus dem einen UIThread erfolgen darf, weil sonst Schlimme Dinge ™ passieren?

Gruß,
Martin

Hallo!

Hi

War das nicht auch unter Java so, dass der Zugriff auf UI
Elemente ausschließlich aus dem einen UIThread erfolgen darf,
weil sonst Schlimme Dinge ™ passieren?

xD stimmt schon, in diesem Fall ist aber nicht Swing/AWT schuld. Mit einem einfachen boolean Flag passiert das gleiche:
public class WTF {

static boolean condition = true;

private static void foo(final int width, final int height) {
System.out.println(„Funktion aufgerufen“);
if (! condition) {
System.out.println(„Funktion ausgeführt“);
} else {
new Thread() {
public void run() {
System.out.println(„Schleife betreten“);
while (condition) {
// System.out.println(„Schleife…“);
}
System.out.println(„Schleife verlassen“);
foo(width, height);
System.out.println(„Thread beendet“);
}
}.start();
}
}

public static void main(String[] args) throws InterruptedException {
foo(300, 200);
Thread.sleep(5);
condition = false;
System.out.println(„Variable geandert [condition=false]“);
}
}
Ausgabe:
Funktion aufgerufen
Schleife betreten
Variable geandert [condition=false]Dann bleibt das Programm in der Schleife hängen.
Hab aber den Fehler gefunden. Abhängig von Prozessor, Betriebssystem, wasweißich, wir die Schleifenbedingung zwischengespeichert und nicht mehr aktuallisiert. Weiß der Geier, warum Java das so „optimiert“. Verhindern lässt sich das aber ganz einfach durch volatile:
static volatile boolean condition = true;
Danke für deine Antwort!

Grüße,
Keks

Hallo.

Hab aber den Fehler gefunden. Abhängig von Prozessor,
Betriebssystem, wasweißich, wir die Schleifenbedingung
zwischengespeichert und nicht mehr aktuallisiert. Weiß der
Geier, warum Java das so „optimiert“. Verhindern lässt sich
das aber ganz einfach durch volatile:
static volatile boolean condition = true;

Multithreading hat so seine Stolpersteinchen. Caching von Variablen in einzelnen Threads ist eins davon, was du mit volatile verhindern kannst. Es hat aber durchaus seinen Sinn, weil Zugriffe auf die nicht-volatile Variablen beschleunigt werden können.
Aber auch schon ein einfaches i++ kann Probleme machen. Wenn i von 2 Threads zugegriffen wird, können „seltsame“ Dinge passieren. Wenn z.B. beide Threads quasi gleichzeitig so einen Befehl ausführen, würde man ja erwarten, dass i am Ende um 2 größer ist als vorher. Es kann aber auch sein, dass i nur um 1 größer ist, je nachdem, wann genau die Taskwechsel stattfinden. Das kann man dann z.B. mit synchronized-Blöcken vermeiden.

Sebastian.