Multithreading: When would I use a Join?

I see online that it says I use myThread.Join(); when I want to block my thread until another thread finishes. (One of the things I don't get about this is what if I have multiple threads).

But generally, I just don't get when I'd use .Join() or a condition that it's useful for. Can anyone please explain this to me like I'm a fourth grader? Very simple explanation to understand will get my answer vote.


Let's say you want to start some worker threads to perform some kind of calculation, and then do something afterwards with all the results.

List<Thread> workerThreads = new List<Thread>();
List<int> results = new List<int>();

for (int i = 0; i < 5; i++) {
    Thread thread = new Thread(() => {
        Thread.Sleep(new Random().Next(1000, 5000));
        lock (results) {
            results.Add(new Random().Next(1, 10));
        }
    });
    workerThreads.Add(thread);
    thread.Start();
}

// Wait for all the threads to finish so that the results list is populated.
// If a thread is already finished when Join is called, Join will return immediately.
foreach (Thread thread in workerThreads) {
    thread.Join();
}

Debug.WriteLine("Sum of results: " + results.Sum());

Oh yeah, and don't use Random like that, I was just trying to write a minimal, easily understandable example. It ends up not really being random if you create new Random instances too close in time, since the seed is based on the clock.


In the following code snippet, the main thread calls Join() which causes it to wait for all spawned threads to finish:

static void Main()
{
    Thread regularThread = new Thread(ThreadMethod);
    regularThread.Start();

    Thread regularThread2 = new Thread(ThreadMethod2);
    regularThread2.Start();

    // Wait for spawned threads to end.
    regularThread.Join();
    Console.WriteLine("regularThread returned.");

    regularThread2.Join();
    Console.WriteLine("regularThread2 returned.");
}

Note that if you also spun up a thread from the thread pool (using QueueUserWorkItem for instance), Join would not wait for that background thread. You would need to implement some other mechanism such as using an AutoResetEvent.

For an excellent introduction to threading, I recommend reading Joe Albahari's free Threading in C#