As some others suggested ("apples and oranges"), I view these two methods as orthogonal. The assumption assumed here is that one chooses one or the other: we will use locks and shared resources, or we will use messaging, which makes the other unnecessary, or perhaps the other is not even available.
Like, say, a metacricular evaluator, it is unclear what the real primitives are here. For example, to implement messaging, you probably need atomic CAS and some semantics of memory visibility, or perhaps some lock and general state. You can implement atomic operations in terms of locks or implement locks in terms of atomic operations (as Java does in java.util.concurrent.locks ).
Similarly, although, admittedly stretched, it is possible to implement blocking with the transmission of messages. To ask which one works best does not make much sense in general, because it really is more a question of which ones are built in terms. Most likely, one that is at a lower level may be better managed by a programmer than one that is built at the top, as was the case with manual transmissions until recently (quite a bit of debate there too).
Typically, the messaging approach is not welcomed for better performance, but rather for security and convenience, and it usually sells, depriving the programmer of control over locking and sharing. As a result, he stakes against the programmer's capabilities; if the programmer cannot get the lock, he cannot do it badly and slow down the program. Many, like discussions about manual memory management and garbage collection, some argue that they are "good drivers", making the most of manual control; others, especially those that implement and promote the use of the garbage collector, argue that collectively, the collector can do a better job than the "not-so-good drivers" with manual control.
There is no absolute answer. The difference here will be related to the level of skills of programmers, and not with the tools that they may possess.