Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java doesn't break a while when runs in Linux [duplicate]

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!

like image 988
dgnin Avatar asked Dec 19 '10 15:12

dgnin


4 Answers

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.

like image 154
Paul Tomblin Avatar answered Nov 01 '22 10:11

Paul Tomblin


end must be volatile since its shared between two threads!

like image 30
dacwe Avatar answered Nov 01 '22 10:11

dacwe


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

like image 34
Lucero Avatar answered Nov 01 '22 09:11

Lucero


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.

like image 34
finnw Avatar answered Nov 01 '22 11:11

finnw