Ваши фрагменты кода немного вводят в заблуждение из-за использования типа делегата (ThreadStart). Важно знать, что в любой среде STA Threaded существует ровно один поток, который считается потоком «UI». Все объекты пользовательского интерфейса должны быть созданы и взаимодействовать в этом потоке.
Таким образом, Dispatcher используется для нескольких вещей, которые проще всего понять - использовать его из фонового потока, чтобы вернуть то, что вы вызываете, в поток пользовательского интерфейса. Таким образом, то, что вы вставляете туда, не совсем «потокобезопасно», но гарантированно вызывается в потоке пользовательского интерфейса. Если вы поместите все, что делаете, в поток пользовательского интерфейса, он будет вызываться один за другим, а не одновременно.
BeginInvoke - это асинхронный вызов для помещения делегата в очередь потока пользовательского интерфейса, в то время как Invoke - синхронный вызов. Что действительно поражает, так это то, что вы можете вызывать Invoke из потока пользовательского интерфейса, который будет блокировать, помещать ваш делегат в очередь и переходить к следующим элементам в очереди, в конце концов вызывая то, что он просто Invoke'd.
Еще одна важная вещь, которую нужно иметь в виду, это то, что Dispatcher - это очередь с приоритетами. Так что это не чистая очередь в смысле «первым пришел-первым вышел», потому что то, где вы вставлены в очередь, зависит от вашего приоритета, и вполне возможно, что в очередь будет помещено достаточно вещей, чтобы ваш вызванный метод никогда не выполнялся .