Search code examples
javamultithreadingswingshared-memoryevent-dispatch-thread

Sequential use of shared variable in Java


I am working on a java GUI application. On some event (eg. button click) I want to read large ammount of data from a file in a new worker thread and store it into shared variable. Then from this worker thread I want to invoke EDT (Event Dispatching Thread) and use the data.

There is no concurrent accesing of the data - just create the data in one thread and when finished, use it in another thread.

I am not sure if invoking EDT from worker thread makes sure that EDT will see the updated data or if it is possible that EDT will only work with some old cashed version.

I don't want to get into using volatile fields and synchronised collections because of the complicated structure of my data class and because I don't want to make my code any slower using unnecessary synchronization.

pseudocode example:

EDT: MyType data;

EDT: start new Worker thread;
Worker: loadDataFromFileInNewThread(data);
Worker: invokeEDT; //using java.awt.EventQueue.invokeLater
EDT: use data;

Is this usage of shared memory alright or do I have to force EDT to use updated version somehow?


Solution

  • On the worker thread, calling java.awt.EventQueue.invokeLater ultimately locks java.awt.EventQueue.pushPopLock before enqueueing your Runnable. This means your worker synchronized on that lock at this point.

    On the EDT side of things, the EDT is in a loop calling java.awt.EventQueue.getNextEvent to receive and process work. getNextEvent locks java.awt.EventQueue.pushPopLock before dequeueing your Runnable.

    At this point we know that both your worker thread and the EDT have both synchronized on the same object, which creates a memory flush point between the two threads, according to the JMM.

    Thus, in your specific scenario, you do not need additional synchronization or volatile to guarantee that the EDT sees up-to-date information created by your worker thread -- as long as your worker thread stops modifying the shared data after having called invokeLater (which would be a best practice anyway).

    Implementation detail: Older versions of Java do not use a java.util.concurrent.locks.Lock, but rather use the synchronized method flag on the EventQueue's methods. However, the exact same rules apply as described above with the Lock.