Search code examples
javaconcurrencyactionlistenersynchronizedvolatile

Java: Concurrency inside ActionListener.actionPerformed


today I started deal with concurrency in Java (probably that was bad idea...)

I read some articles about it. At the beginning I understood it but now I am confused...

I'm going straight to the point. Suppose we have this class

public class Test implements ActionListener
{
    private boolean bool;

    public void process()
    {
        if (bool)
            // ...

        return bool;
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        // We can suppose that this method belongs to JButton or so...
        // And if I am not wrong then this method is fired in EDT, so it means it runs in
        // other thread (Event Dispatch Thread) in contrast with this class... So there are
        // two threads...

        bool = ... ? true : false;
    }

    // ...
}

My confusion:

In actionPerformed() we modify the value of property bool and in the same time we can access the property inside process() (again if I am not wrong)... For me it seems that there can occur to some error or so... My solution is that property bool should be volatile or method process() should be tagged as synchronized and statement

bool = ... ? true : false;

should be as:

synchronized (this)
{
    bool = ... ? true : false;
}

This is little primitive example, but we can consider bool property as Object, String, etc... and in actionPerformed() we will set it to null and in process() will be thrown a NullPointerException for example...

What you think? I want to know why anyone use synchronizing inside listeners... I have not found anyone...

Thanks

Regards brolinko

EDIT #1: process() is never called within EDT... When I create an instance of Test for example in main() method then the instance runs inside a thread as main() and in main() I can call the process() ... So there are two threads in this case if I am not wrong...


Solution

  • You're not wrong, if a variable is used by two or more threads, writes should be made visible by using the appropriate memory barriers (synchronized/volatile/java.util.concurrent).

    In this case though, the question is: is process() not also called from the EDT? If it is, there are no multiple threads to talk about and hence the code works, albeit dangerously unsafe.

    Update: You're saying process() isn't called from the EDT. Your code will still happen to work because although you don't put a memory barrier on your write, the implementation of the EDT does. In theory, relying on this is a dangerous idea because there's no guarantee this will stay this way. In practice, there are so many brittle AWT applications out there that it's unlikely to change. (As pointed out by @jtahlborn, this barrier still only applies to calls from within the EDT)