My reading of JLS 12.5 makes me think the assertion in the code sample should never trigger—but it does in my multithreaded code. (The JLS doesn't specify threading in the section). But whether or not my reading is correct is beside the point. I want to get this to always be true.
public class MainWindow extends JFrame {
private final JLabel label;
public MainWindow() {
label = new JLabel();
pack();
setVisible(true);
}
public JLabel getLabel() {
Assert.assertNotNull(label);
return label;
}
}
The obvious answer is to wrap the innards of the constructor in a synchronized block and to mark the getter synchronized as well. Is there a better way?
FWIW, the other thread is getting a reference to the window with this code inside a junit test:
private MainWindow findMainWindow() {
for (Frame frame : Frame.getFrames()) {
if (frame instanceof MainWindow) {
return (MainWindow)frame;
}
}
return null;
}
(BTW, I'm running JDK6 on a Mac)
Update:
I even tried synchronizing it and it still doesn't work. Here's the code:
public class MainWindow extends JFrame {
private final JLabel label;
public MainWindow() {
synchronized(this) {
label = new JLabel();
}
}
public synchronized JLabel getLabel() {
Assert.assertNotNull(label);
return label;
}
}
Update 2:
Here's the change that fixed it:
private MainWindow findMainWindow() throws Exception {
final AtomicReference<MainWindow> window = new AtomicReference<MainWindow>();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
for (Frame frame : Frame.getFrames()) {
if (frame instanceof MainWindow) {
window.set((MainWindow) frame);
return;
}
}
}
});
return window.get();
}