In summary, you want to
- Do as little as possible in the body of a lock.
- Even though it’s difficult and for many cases next to impossible, return your application to a pristine state. i.e. “carefully implement the bodies of locks that do mutations so that in the event of an exception, the mutated resource is rolled back to a pristine state before the lock is released.”
- Don’t abort threads for the reason of leaving you application in an inconsistent state (unrecoverable). The thread should wait for a synch object and then return from the running methods in a consistent manner.