I read a really good blog some time ago which discuss this issue (mentioned by Karl Bielefeldt), what it basically says is that it is very dangerous to try and make the UI kit thread safe, as it introduces possible deadlocks and depending on how it's implemented, race conditions into the framework.
There is also a performance consideration. Not so much now, but when Swing was first released it was heavily criticised for it's performance (been bad), but that wasn't really Swing's fault, it was people's lack of knowledge with how to use it.
SWT enforces the concept of thread safety by throwing exceptions if your violate it, not pretty, but at least you're made aware of it.
If you look into the painting process, for example, the order in which elements are painted is very important. You don't want the painting of one component to have a side effect on any other part of the screen. Imagine if you could update a label's text property, but it was painted by two different threads, you could end up with a corrupted output. So all painting is done within a single thread, normally based on the order of requirements/requests (but sometimes condensed to reduce the number of actual physical paint cycles)
You mention changing from Swing to JavaFX, but you'd have this problem with just about any UI framework (not just thick clients, but web as well), Swing just seems to be the one which highlights the problem.
You could design a intermediate layer (a controller of a controller?) whose job it is to ensure that calls to the UI are synchronised correctly. It's impossible to know exactly how you might design your non-UI parts of your API from the perspective of the UI API and most developers would complain that any thread protection implemented into the UI API was to restrictive or didn't meet their needs. Better to allow you to decide how you want to solve this issue, based on your needs
One of the biggest issues you need to consider is the ability to justify a given order of events, based on known inputs. For example, if the user resizes the window, the Event Queue model guarantees that a given order of events will occur, this might seem simple, but if the queue allowed events to triggered by other threads, then you can no longer guarantee the order in which the events might occur (a race condition) and all of sudden you have to start worrying about different states and not doing one thing until something else happens and you start having to share state flags around and you end up with spaghetti.
Okay, you might solve this by having some kind of queue which ordered the events based on the time they were issued, but isn't that what we already have? Besides, you could still no guarantee that thread B would generate it's events AFTER thread A
The main reason people get upset about having to think about their code, is because they are made to think about their code/design. "Why can't it be simpler?" It can't be simpler, because it's not a simple problem.
I remember when the PS3 was been released and Sony was up-talking the Cell processor and it's ability to perform separate lines of logics, decode audio, video, load and resolve model data. One game developer asked, "That's all awesome, but how do you synchronize the streams?"
The problem the developer was talking about was, at some point, all those separate streams would need to be synchronized down to single pipe for output. The poor presenter simply shrugged as it wasn't a issue they were familiar with. Obviously, they've had solutions to solve this problem now, but it has funny at the time.
Modern computers are taking a lot of input from a lot of different places simultaneously, all that input needs to be processed and delivered to the user in away which doesn't interfere with the presentation of other information, so it's a complex problem, with out a single simple solution.
Now, having the ability to switch frameworks, that's not an easy thing to design for, BUT, take MVC for a moment, MVC can be multi layered, that is, you could have a MVC which deals directly with managing the UI framework, you could then wrap that, again, in a higher layer MVC which deals with interactions with other (potentially multi threaded) frameworks, it would be the responsibility of this layer to determine how the lower MVC layer is notified/updated.
You would then use coding to interface design patterns and factory or builder patterns to construct these different layers. This means, that you multithreaded frameworks become decoupled from the UI layer through the use of a middle layer, as an idea.