In this example I have a simple JFrame containing a JButton with an ActionListener tied to it. This AcitonListener just changes a boolean flag that should allow the program to complete.
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");
}
}
This never prints "Finished", and after the button has been clicked once prints
Waiting
Button was clicked!
However, if I modify the while loop to read
while(!flag[0]){
System.out.println("I should do nothing. I am just a print statement.");
}
This 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 this probably isn't the proper way to wait on an action, but nonetheless I am interested in knowing why Java behaves this way.
The likeliest reason is that flag[0] = true;
is executed on the UI thread, whereas while(!flag[0])
is executed on the main thread.
Without synchronization, there is no guarantee that the change made in the UI thread will be visible from the main thread.
By adding the System.out.println
you introduce a synchronization point (because the println method is synchronized
) and the problem gets solved.
You could make flag
a volatile instance or class boolean variable (not an array), or, more simply, put whatever code you want executed on the button being pressed in the listener itself.
For reference, the code with a volatile 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");
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.