From a fundamental perspective, threads are seriously flawed as a computation model because they are wildly nondeterministic, as the "Nondeterminism and Threads" sidebar describes. The programmer's job is to prune away that nondeterminism. We have developed tools to assist in the pruning: Semaphores, monitors, and more modern overlays on threads offer the programmer ever more effective pruning. But pruning a wild mass of brambles rarely yields a satisfactory hedge.
We must and can build concurrent computation models that are far more deterministic, and we must judiciously and carefully introduce nondeterminism where needed. Nondeterminism should be explicitly added to programs, and only where needed, as it is in sequential programming. Threads take the opposite approach. They make programs absurdly nondeterministic and rely on programming style to constrain that nondeterminism to achieve deterministic aims.