多线程编程是现代软件开发中的一项关键技术,它允许程序同时执行多个任务,从而提高应用程序的响应性和性能。C#提供了丰富的线程管理功能,包括线程的创建、同步、通信和池化等。本文将深入探讨C#中线程的工作原理、使用场景、最佳实践以及一些高级技巧。
线程的基本概念
在C#中,线程是操作系统中最小的执行单元,是程序执行的最小单位。每个线程都有自己的调用栈和状态信息。
主线程与后台线程
- 主线程:程序运行的主要线程,通常用于UI交互。
- 后台线程:用于执行后台任务,不会阻止程序退出。
线程的生命周期
线程的生命周期包括新建、就绪、运行、挂起、恢复和终止等状态。
核心API
Thread
类
Thread
类是C#中最基本的线程管理类,提供了创建和控制线程的方法。
ThreadPool
类
ThreadPool
是一个线程池,用于管理和复用线程,以提高资源利用率和性能。
Task
类
Task
是.NET中用于表示异步操作的类,它基于线程池来执行。
Mutex
、Semaphore
和Monitor
这些类用于线程同步,防止多个线程同时访问共享资源。
创建和启动线程
使用Thread
类
代码语言:javascript复制using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Thread newThread = new Thread(() => Console.WriteLine("Hello from a new thread!"));
newThread.Start();
Console.WriteLine("Hello from the main thread!");
}
}
使用ThreadPool
代码语言:javascript复制using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine("Hello from ThreadPool thread!");
});
Console.WriteLine("Hello from the main thread!");
}
}
使用Task
类
代码语言:javascript复制using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Task myTask = Task.Run(() =>
{
Console.WriteLine("Hello from a Task!");
});
await myTask;
Console.WriteLine("Hello from the main thread!");
}
}
线程同步
使用lock
关键字
代码语言:javascript复制using System;
using System.Threading;
class Program
{
private static readonly object lockObject = new object();
private static int sharedResource = 0;
static void Main(string[] args)
{
Thread thread1 = new Thread(Increment);
Thread thread2 = new Thread Increment);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Shared resource value: {sharedResource}");
}
static void Increment()
{
lock(lockObject)
{
for (int i = 0; i < 1000000; i )
{
sharedResource ;
}
}
}
}
使用Mutex
代码语言:javascript复制using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Mutex mutex = new Mutex();
Task task1 = Task.Run(() =>
{
mutex.WaitOne();
try
{
Console.WriteLine("Task 1 is executing.");
Thread.Sleep(2000);
}
finally
{
mutex.ReleaseMutex();
}
});
Task task2 = Task.Run(() =>
{
mutex.WaitOne();
try
{
Console.WriteLine("Task 2 is executing.");
Thread.Sleep(2000);
}
finally
{
mutex.ReleaseMutex();
}
});
Task.WhenAll(task1, task2).Wait();
}
}
使用Semaphore
代码语言:javascript复制using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Semaphore semaphore = new Semaphore(1, 1);
Task task1 = Task.Run(() =>
{
semaphore.WaitOne();
try
{
Console.WriteLine("Task 1 is executing.");
Thread.Sleep(2000);
}
finally
{
semaphore.Release();
}
});
Task task2 = Task.Run(() =>
{
semaphore.WaitOne();
try
{
Console.WriteLine("Task 2 is executing.");
Thread.Sleep(2000);
}
finally
{
semaphore.Release();
}
});
Task.WhenAll(task1, task2).Wait();
}
}
使用Monitor
代码语言:javascript复制using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static object lockObject = new object();
private static int sharedResource = 0;
static void Main(string[] args)
{
Task task1 = Task.Run(() =>
{
for (int i = 0; i < 1000000; i )
{
Monitor.Enter(lockObject);
try
{
sharedResource ;
}
finally
{
Monitor.Exit(lockObject);
}
}
});
Task task2 = Task.Run(() =>
{
for (int i = 0; i < 1000000; i )
{
Monitor.Enter(lockObject);
try
{
sharedResource ;
}
finally
{
Monitor.Exit(lockObject);
}
}
});
Task.WhenAll(task1, task2).Wait();
Console.WriteLine($"Shared resource value: {sharedResource}");
}
}
线程间通信
使用AutoResetEvent
和ManualResetEvent
代码语言:javascript复制using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
static void Main(string[] args)
{
Task producerTask = Task.Run(() =>
{
for (int i = 0; i < 5; i )
{
Console.WriteLine($"Produced: {i}");
autoResetEvent.Set();
Thread.Sleep(1000); // Simulate work
}
});
Task consumerTask = Task.Run(() =>
{
for (int i = 0; i < 5; i )
{
autoResetEvent.WaitOne();
Console.WriteLine($"Consumed: {i}");
}
});
Task.WhenAll(producerTask, consumerTask).Wait();
}
}
使用BlockingCollection
代码语言:javascript复制using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
BlockingCollection<int> collection = new BlockingCollection<int>(new ConcurrentQueue<int>(), 10);
CancellationTokenSource cts = new CancellationTokenSource();
Task producerTask = Task.Run(() =>
{
for (int i = 0; i < 20; i )
{
collection.Add(i);
Console.WriteLine($"Produced: {i}");
Thread.Sleep(1000); // Simulate work
}
cts.Cancel();
});
Task consumerTask = Task.Run(() =>
{
try
{
foreach (int item in collection.GetConsumingEnumerable(cts.Token))
{
Console.WriteLine($"Consumed: {item}");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Consuming cancelled.");
}
});
Task.WhenAll(producerTask, consumerTask).Wait();
}
}
高级技巧
线程局部存储
使用ThreadLocal<T>
来存储线程特定的数据。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static ThreadLocal<int> localData = new ThreadLocal<int>(() => 0);
static void Main(string[] args)
{
Task task1 = Task.Run(() =>
{
localData.Value = 1;
Console.WriteLine($"Task 1 local data: {localData.Value}");
});
Task task2 = Task.Run(() =>
{
localData.Value = 2;
Console.WriteLine($"Task 2 local data: {localData.Value}");
});
Task.WhenAll(task1, task2).Wait();
}
}
参数化线程
在创建线程时传递参数。
代码语言:javascript复制using System;
using System.Threading;
class Program
{
static void ThreadMethod(object o)
{
Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} says: {o}");
}
static void Main(string[] args)
{
Thread newThread = new Thread(new ParameterizedThreadStart(ThreadMethod));
newThread.Start("Hello from a thread!");
Console.WriteLine($"Main thread says: {o}");
}
}
定时器线程
使用Timer
类来周期性地执行任务
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Timer timer = new Timer(TimerCallback, null, 0, 1000);
Console.WriteLine("Press enter to exit...");
Console.ReadLine();
}
private static void TimerCallback(object state)
{
Console.WriteLine("Timer callback executed!");
}
}
异步局部变量
使用AsyncLocal<T>
来存储异步上下文中的数据。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static AsyncLocal<int> localData = new AsyncLocal<int>();
static void Main(string[] args)
{
localData.Value = 1;
Task task1 = Task.Run(async () =>
{
await Task.Delay(1000);
Console.WriteLine($"Task 1 local data: {localData.Value}");
});
Task task2 = Task.Run(async () =>
{
await Task.Delay(1000);
Console.WriteLine($"Task 2 local data: {localData.Value}");
});
Task.WhenAll(task1, task2).Wait();
}
}
性能优化
避免过度线程化
创建线程是有成本的,过多的线程会导致上下文切换和资源竞争。
使用线程池
使用线程池可以减少线程创建和销毁的开销。
优化锁的使用
尽量减少锁的使用范围和持有时间,使用读写锁来优化读多写少的场景。
减少线程同步
使用无锁编程技术,如Interlocked
类,来减少线程同步的开销。