The other option we have in order for a piece of code to be executed within the context of a specific thread (the main/UI thread specifically) is the Queue approach. Basically, it relies on the capability of the threads to maintain a queue of pieces of code to be executed.
This capability has some pitfalls; for example, event in the queue of a thread that gets destroyed, either because it has come to its end or has been terminated from outside, or maybe it has been disposed of and never been executed. But again, I am not going to discuss corner cases here. In most UI-related situations, you most likely want to queue code executions within the main/UI thread, which are extremely unlikely to be terminated before you need that code to be actually executed.
Look at the Queue part in Figure 11.1. From the diagram of code execution in the three situations (no sync, Sync, and Queue), you can notice how the gray code gets executed in the context of the UI thread...