Go study java.util.concurrent. It's one of the absolute best libraries ever written by some of the smartest programmers I have ever seen.
The primary question is "Do I really need to wait or do I just need to be consistent?" 90% of the time the answer is that consistent is good enough.
Lock-free data structures are not a panacea. They don't always do as well as locks in the face of contention. However, if you have that much contention, congratulations, you have an actual spot you really need to optimize.
By default, though, lock-free data structures protect you from so much fail it's ridiculous. I don't dread concurrent programming if I have a good lock-free data structure library.
That having been said, if you really have to wait (normally for hardware access), then you MUST do certain things. Your "lock" MUST be as small as possible--if it isn't "lock with timeout", "single small action that always goes to completion even if error occurs", "unlock"--YOU HAVE FAILED. START OVER. Also, note the "timeout" portion of the lock. "Timeout" MUST be handled and IS NOT NECESSARILY AN ERROR.
Now, these don't get all the situations. People who need "transactions" have hard problems. People who have high contention have hard problems.
However, I can count the number of times I genuinely needed to deal with contention or transactions on one hand and still have two fingers left over.
Whereas, I have lost count of the number of times that I cleared out all manner of bugs simply by switching to a lock-free data structure.