Dynamic detection detects errors only for the execution path chosen at runtime. This is a disadvantage, because a program must be run many times to test all code paths. In contrast, a static preventor is more thorough; it tests all possible code paths at once.
By exploiting runtime information, a dynamic detector can accurately determine which locks guard which data. A lack of this information often blinds a static preventor. For example, when a lock is acquired through a pointer a static preventor does not know which lock the pointer references. Instead, a static preventor must rely on heuristics, assumptions, and explicit user source code annotations to determine which locks guard which data. This is cumbersome and inaccurate.
A static preventor would benefit from a high-level language which directly supports multi-threading. Such a language would allow locking semantics to be more easily inferred--and the accuracy problem of static preventors to be ameliorated.
A dynamic detector is more useful as an afterthought to coding. After a program is written, bugs may be discovered. A static preventor is not suitable to correct these bugs, because using a static preventor requires adding time-consuming annotations to the source code.
To fix synchronization problems, static and dynamic checkers offer complementary opportunities: where one method excels the other is often lacking. The advantages of each method can be leveraged by using a combination of both methods. This can instill a degree of confidence that neither method alone could provide.