Threads themselves can be used as synchronization primitives when one thread specifically waits for another thread to complete.
The waiting thread does not continue processing until the target thread has finished running all of its application code. Compared to other synchronization techniques, there is little cooperation in this synchronization mechanism.
A thread that is used as a synchronization primitive does not have the concept of an owner, such as in other synchronization techniques. A thread just waits for another to finish processing and end.