While Java loops do not check their conditions if there is no body?

In this example, I have a simple JFrame containing a JButton bound to an ActionListener. This AcitonListener simply changes the boolean flag, which should allow the program to terminate.

public class Test { public static void main(String[] args){ final boolean[] flag = new boolean[1]; flag[0] = false; JFrame myFrame = new JFrame("Test"); JButton myButton = new JButton("Click Me!"); myButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { System.out.println("Button was clicked!"); flag[0] = true; } }); myFrame.add(myButton); myFrame.setSize(128,128); myFrame.setVisible(true); System.out.println("Waiting"); while(!flag[0]){} System.out.println("Finished"); } } 

It never prints "Finished", and after clicking the button after printing

 Waiting Button was clicked! 

However, if I change the while loop to read

 while(!flag[0]){ System.out.println("I should do nothing. I am just a print statement."); } 

It works! The printout looks like

 Waiting I should do nothing. I am just a print statement. I should do nothing. I am just a print statement. .... I should do nothing. I am just a print statement. Button was clicked! Finished 

I understand that this is probably not the way to wait for action, but nonetheless, I am interested to know why Java behaves in this way.

+6
source share
1 answer

The most likely reason is flag[0] = true; is executed in the user interface thread, while while(!flag[0]) is executed in the main thread.

Without synchronization, there is no guarantee that changes made to the user interface stream will be visible from the main stream.

By adding System.out.println , you enter the synchronization point (because the println method is synchronized ), and the problem is resolved.

You can make flag a volatile instance variable or a boolean class (and not an array), or, more simply, put any code you want to execute by clicking a button in the listener itself.


For reference, code with a mutable variable would look like this:

 private static volatile boolean flag; public static void main(String[] args) { JFrame myFrame = new JFrame("Test"); JButton myButton = new JButton("Click Me!"); myButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { System.out.println("Button was clicked!"); flag = true; } }); myFrame.add(myButton); myFrame.setSize(128, 128); myFrame.setVisible(true); System.out.println("Waiting"); while (!flag) { } System.out.println("Finished"); } 
+7
source

All Articles