0

Does SwingUtilities.invokeLater provides synchronization?

Example:

public class Threads {
    public static void main(String[] args) {
        new Thread(new Runnable() {     
            @Override
            public void run() {
                new Threads().test();
            }
        }).start();
    }
    
    List<Integer> list = new ArrayList<>(); 
    
    void test() {
        System.out.println(Thread.currentThread().toString());  
        
        for (int i=0; i<10000000; i++) {
            list.add(i);
        }
        
        SwingUtilities.invokeLater(() -> {                          
            System.out.println(Thread.currentThread().toString());
            list.forEach(System.out::println);  // list auto synchronized?      
        });
    }
}

Would be list synchronized when I read values from the list in AWT thread?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
VextoR
  • 5,087
  • 22
  • 74
  • 109
  • 1
    This code doesn't have a race condition, because every thread creates it's own `List` (no synchronization needed) and then calls `SwingUtilities.invokeLater`, establishing a happens-before relationship. The individual lists are also not modified after `SwingUtilities.invokeLater` has been invoked, so the event thread doesn't need to do any synchronization – Johannes Kuhn May 05 '22 at 21:00
  • Your language is not correct, but I think you understand this correctly. When you use Swing.invokeLater, it executes the Runnable on the UI Thread. So while the list is not *synchronized*, you are essentially running on only one thread – ControlAltDel May 05 '22 at 21:01
  • `SwingUtilities.invokeLater()` offers nothing in the way of synchronization. If you need synch locks you'll need to look into synchronized blocks or some other tool like a `Semaphore` – Ryan May 05 '22 at 21:21
  • 1. If `list` were `static` you'd have a problem. But each `Threads` gets its own `list`, so no problem there. 2. Yes, technically `list` needs to be synchronized some how, `invokeLater` doesn't do that. 3. But I think a lambda capturing an effectively final variable like this might do some sort of happens-before, you should probably investigate that aspect to learn more about when exactly this happens. – markspace May 05 '22 at 21:51
  • @markspace it's `SwingUtilities.invokeLater` that creates a happens-before, so all the writes to the `ArrayList` are visible in the event thread. – Johannes Kuhn May 05 '22 at 21:56
  • @JohannesKuhn Are you sure? Because I don't recall seeing that in the docs. Can you point out to me how you know that `invokeLater()` creates a happens-before? – markspace May 05 '22 at 23:23
  • @markspace see https://stackoverflow.com/questions/21147240/is-happens-before-relation-given-in-case-of-invokelater-or-invokeandwait for that. – Johannes Kuhn May 06 '22 at 00:29
  • @JohannesKuhn I think you're reading that wrong. The accepted answer says *"Code which relies on the thread safety of `repaint` or other methods is broken and is not guaranteed to behave properly"* and `repaint` calls `invokeLater`. I think what TrashGod is saying is that they really wish that `invokeLater` made a guarantee, but they admit that it doesn't. – markspace May 06 '22 at 00:41
  • 1
    @markspace whether `repaint` is thread safe or not, does not say anything about the question whether `invokeLater` establishes a *happens-before* relationship. – Holger May 10 '22 at 12:45
  • @Holger We kinda covered that in a roundabout way, but to be clear, `invokeLater` does not document that it creates any kind of happens before, therefore we have to say that it does not. If you peek inside the code, you can see that it uses a concurrent queue which does create happens before, but this kind of implementation detail cannot be relied on and future code might break if it doesn't follow the external documentation. – markspace May 10 '22 at 14:09
  • 1
    @markspace it would be a very surprising behavior if the tool documented to be the solution to a problem turns out to be subject to the problem. However, I was *not* discussing whether `invokeLater` is thread safe or not. I was responding to your comment that was using a statement about `repaint` to draw conclusions about `invokeLater`. Nothing allows such conclusions. Neither should you speculate “what TrashGod is saying” in such a far fetched way. – Holger May 10 '22 at 15:18

2 Answers2

0

Does SwingUtilities.invokeLater provides synchronization?

No. It just runs its parameter later.

Would be list synchronized when I read values from the list in AWT thread?

No, but it doesn't need to be. It is sent to invokeLater after it was created and assigned with values. It doesn't change at any later time so it won't be changed while the code sent to invokeLater is executed.

  • 1
    Without checking the actual implementation, I think that publishing the Runnable to the event thread will involve a thread-safe measure, which will establish a happens-before relationship. – Mark Rotteveel May 09 '22 at 12:00
  • 2
    @MarkRotteveel it will, but we should by no means create the impression that there’s something matching the question’s wording (assuming list to be “synchronized”). – Holger May 10 '22 at 12:47
-1

To summarize some facts:

  • in general Swing is not threadsafe
  • everything GUI-related runs on the awt Event Dispatching Thread
  • EDT does not guarantee the order of execution
  • EDT dispatches time-consuming work to worker threads (> worker pattern)
  • EDT should execute only small GUI-related tasks otherwise UI will freeze
  • SwingUtilities.invokeLater is based on awt.EventQueue.invokeLater

So if you have SwingUtilities.invokeLater and give it a Runnable (your function), this Runnable will be put into an event-queue for the dispachter thread (EDT) which will execute your Runnable asynchronously.

To be exact:

Yes, your code as part of invokeLater will run in parallel (if that is what you meant) on the EDT which runs asychronously to the main thread.

No, it is not synchronized in matter of "another thread entering it" because it is designated only to be executed by the EDT.

Although it is not part of the question: EDT should not be misused in that way. Instead you should put this task into a worker thread and let EDT be for what it has been created: dispatching GUI related tasks to worker threads.

user3192295
  • 358
  • 2
  • 13