Locking objects can be the cause of deadlocks if you're not careful. Suppose you have two data structures A and B that need to have data in them synchronised. Thread 1 updates A with new information, then updates B to match. Thread 2 updates B with new information, then updates A to match.
So the workflow for thread 1 might be:
1. Receive new data.
2. Lock A.
3. Update A.
4. Lock B.
5. Update B to match.
6. Unlock B.
7. Unlock A.
8. Goto 1.
Note that we have A and B locked at the same time so somebody else doesn't modify B until we've got our changes synchronized across the two.
Suppose threads 1 and 2 both receive new information at the same time and need to update the data structures. The order in which things could happen is totally unpredictable, but it could be:
1. Thread 1 locks A
2. Thread 1 updates A
3. Thread 2 locks B
4. Thread 2 updates B
5. Thread 1 now needs to update B, so it tries to lock B. B is already locked so it waits.
6. Thread 2 now needs to update A, so it tries to lock A. A is already locked so it waits.
7. Oops - deadlock. The whole program is now permanently stuck.