My point is, by design, an operating system that has a fully async interface can dispense with locks altogether. Resource contention is then properly resolved through queuing. The OS can then strictly enforce a priority scheme on its various queues, preventing an opportunistic thread from dominating the system. Or enabling higher priority requests to be serviced first. But that decision is made intelligently, not as a result of optimizing to minimize context switching.
No locks means this can never happen.
Async style enforces a kind of minimalism that in my opinion simplifies the problem space overall. Obviously, one has to learn different approaches to problem definition and solution to embrace event-driven coding.
To me, in the comparison of linear programming handling an exception when your call stack is 5 levels deep (or maybe 3 in a different use case), having to bubble the appropriate handling at each of those levels, versus async where in your closure you have a 4-line if/else construct that fires off one event for success and a different event for failure, async wins the simplicity competition every time.
If race conditions are an issue, events should be dispatched through a single-threaded finite state machine dispatcher for resolution. Such events can fire up multiple worker threads to do their bidding, but when state changes, that goes through the dispatcher which inherently resolves all races.