From the examples it is difficult to determine which one is correct, if any. A few recommendations / observations, although this may help you answer your question or know what to provide additional information:
First, do I need to sync? Would it make sense for each thread to have an instance of this class? If each instance is local to the stream and is only modified and used in this stream, you do not need to block.
If the purpose of this class and the use of threads is to process a larger set of data in parallel, it may make more sense for the main thread to split the task in some logical way, and then wait until the work flows complete.In this case, instead of managing the threads, consider ThreadPool yourself and wait for the handles. Most of the dirty work is done for you then.
About synchronization / locking in general: if your operation was interrupted between steps, will the data be consistent / valid?
In your example, let's say you have two threads. The first is in the area between .AddRange() and .Count when the second thread enters the function and gets a lock in the list.
Thread 1 works a little more and hits the lock protecting the .Count method and goes into sleep mode. Tempo 2, meanwhile, clears the list and then releases its lock, waking Thread 1 up, which then gets the lock.
In this case, Thread 1 will return 0 from this function when the work was performed by thread 1 to create a list. And then the length of the list will not really be 0, since stream 2 came and populated the list.
In this case, locks around individual list operations interrupt the program, so it makes sense to have one lock surrounding between Clear and the call to Count .
In short, multithreading is a good way to introduce a whole class of subtle bugs related to race conditions that often lead to Heisenbugs .
It is often useful to avoid threads when you can. If you cannot, try organizing your workload in ways that require minimal synchronization (for example, by providing a stream with a dataset at the beginning and then waiting for it to complete, for example, a related example of a thread pool). If you cannot do this, proceed carefully and always ask yourself: "What happens if two threads work in this area."
Hope this helps you in future adventures in multi-threaded code.