You can, of course, encapsulate such a lock order with dedicated classes (or functions/closures) modeling linear types enforcing the sequence of lock A > lock B > unlock B > unlock A. The resulting objects can still be misapplied, but should fail immediately with a runtime error, making it much harder to inadvertently misuse.