Fundamentals 10 min read

C# Multithreading Basics: Introduction, Join, Sleep, and Thread Safety

This article introduces C# multithreading concepts, demonstrates thread creation, memory isolation, data sharing, thread safety with locks, and explains the use of Join and Sleep methods, providing practical code examples and best‑practice guidance for concurrent programming.

Wukong Talks Architecture
Wukong Talks Architecture
Wukong Talks Architecture
C# Multithreading Basics: Introduction, Join, Sleep, and Thread Safety

C# supports multithreading, allowing parallel execution of code where each thread runs independently alongside others. The main thread is created automatically by the CLR and OS, and additional threads can be spawned to achieve concurrency.

class Program { static void Main(string[] args) { Thread thread = new Thread(WriteY); //创建一个线程 thread.Start(); //开始一个线程 for (int i = 0; i < 1000; i++) //主线程执行循环 { Console.Write("x"); } Console.ReadLine(); } static void WriteY() { for (int i = 0; i < 1000; i++) { Console.Write("y"); } } }

Each thread has its own stack, so local variables are isolated. When two threads call the same instance method, they share the instance fields, which can lead to race conditions if not synchronized.

class Program { bool done = false; static void Main(string[] args) { Program p = new Program(); new Thread(p.Go).Start(); p.Go(); Console.ReadKey(); } void Go() { if (!done) { done = true; Console.WriteLine("Done"); } } }

Static fields are shared across all threads, providing another way to share data:

class ThreadTest { static bool done; // Static fields are shared between all threads static void Main() { new Thread(Go).Start(); Go(); } static void Go() { if (!done) { done = true; Console.WriteLine("Done"); } } }

Thread safety can be achieved by using an exclusive lock. C# provides the lock keyword to protect critical sections:

class Program { static bool done = false; static readonly object locker = new object(); static void Main(string[] args) { new Thread(Go).Start(); Go(); Console.ReadKey(); } static void Go() { lock (locker) { if (!done) { Console.WriteLine("Done"); done = true; } } } }

The Join method blocks the calling thread until the target thread finishes, while Thread.Sleep pauses the current thread for a specified duration without consuming CPU cycles. Variants like Thread.Sleep(0) or Thread.Yield() relinquish the current time slice to allow other threads to run.

Thread scheduling is handled by the CLR and the operating system. On a single‑core CPU, threads share time slices (typically ~10 µs). On multi‑core systems, threads can run truly in parallel on different cores, though the OS still interleaves execution for fairness.

Threads differ from processes: a process is an isolated OS entity, while threads share the same process memory space, enabling fast communication but also requiring careful synchronization to avoid data races.

Common uses of multithreading include keeping UI responsive, maximizing CPU utilization while waiting for I/O, parallelizing compute‑intensive workloads, and handling multiple simultaneous server requests. However, improper sharing of mutable state can introduce hard‑to‑reproduce bugs, so encapsulating thread logic in reusable, testable classes and using proper locking is essential.

concurrencycthreadmultithreadingJoinLocksleep
Wukong Talks Architecture
Written by

Wukong Talks Architecture

Explaining distributed systems and architecture through stories. Author of the "JVM Performance Tuning in Practice" column, open-source author of "Spring Cloud in Practice PassJava", and independently developed a PMP practice quiz mini-program.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.