6

I found a mysterious problem with a Java code for homework. A friend program an application which this at the beginning :

public void run() {
    vm.setVisible(true);
    while(!end);
    System.out.println("Finish");
    vm.setVisible(false);
}

The boolean 'end' is false while all the execution and when the user quits the application this happens:

private class CloseSys implements ActionListener {
    public CloseSys() {super();}

        public void actionPerformed(ActionEvent e) {
        System.out.println("CLOSE SYS");
        System.out.println("end: "+end);
        end = true;
        System.out.println("end: "+end);
    }
}

The println shows like the value of 'end' changes to true and logically in my friend's computer (MacOS) the while finish and the application too.

The problem is that in my computer (Ubuntu Linux) the println also shows like the value changes but the while doesn't ends (the "Finish" println is never reached). The funny thing about it is if we put prints into the while... then works!

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
dgnin
  • 1,565
  • 2
  • 20
  • 33

4 Answers4

5

Several other people have mentioned that it should be volatile. One thing nobody seems to have mentioned yet is that you are "busy waiting", which is wrong, wrong, wrongity wrong. If you want to wait for something to happen in another thread, you should use synchronization locks or Semaphores.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
3

end must be volatile since its shared between two threads!

dacwe
  • 43,066
  • 12
  • 116
  • 140
  • Thank you, this solves the problem :) I mark you as solved because I think you were the first answer. I don't know if it is the way of do it. – dgnin Dec 19 '10 at 15:56
  • I was the first by about 17 seconds, but that's fair ehough ;-) – Lucero Dec 19 '10 at 16:09
2

Try to make the end variable volatile - you've been bitten by a multithreading issue (and you have a multi-core CPU).

Here's some info on that: http://www.javamex.com/tutorials/synchronization_volatile_when.shtml

Lucero
  • 59,176
  • 9
  • 122
  • 152
2

It looks like a threading issue.

Try declaring end as volatile, or better still use a CountDownLatch as this avoids hogging a CPU:

private CountDownLatch latch;

public void run() {
    try {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                vm.setVisible(true);
            }
        });
        try {
            latch.await();
            System.out.println("Finish");
        } finally {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    vm.setVisible(false);
                }
            });
        }
    } catch (InterruptedException ex) {
        System.out.println("Interrupt");
        Thread.currentThread().interrupt();
    } catch (InvocationTargetException ex) {
        throw new RuntimeException(ex);
    }
}

private class CloseSys implements ActionListener {    
    public void actionPerformed(ActionEvent e) {
        System.out.println("CLOSE SYS");
        latch.countDown();
    }
}

Note the use of invokeAndWait to change the window visibility from a non-EDT thread.

finnw
  • 47,861
  • 24
  • 143
  • 221
  • Why the need for a CountDownLatch? Why not just Object.wait()? – Sergei Tachenov Dec 19 '10 at 15:51
  • The volatile works, and unfortunately I don't have time now to try the CountDownLatch, but I will try it soon. – dgnin Dec 19 '10 at 15:54
  • @Sergey Tachenov, `Object.wait` is a low-level method and has pitfalls, e.g. `notify`-vs-`notifyAll`, spurious wakeup. You can work around it but then you would be reinventing the wheel. – finnw Dec 20 '10 at 13:08