在C#里,创建线程有多种方式,下面为你详细介绍并给出示例。
1. 使用Thread类
通过Thread
类创建线程是最基础的方式,有两种途径可以启动线程:
- 使用ThreadStart委托:这种方式适用于线程执行的方法没有返回值(即返回类型为
void
)。 - 使用ParameterizedThreadStart委托:当线程执行的方法需要参数时,可以使用这种方式。
下面是具体的示例代码:
using System;
using System.Threading;
class Program
{
static void Main()
{
// 使用ThreadStart委托
Thread thread1 = new Thread(PrintNumbers);
thread1.Start();
// 使用ParameterizedThreadStart委托
Thread thread2 = new Thread(PrintNumbersWithDelay);
thread2.Start(500); // 传递毫秒级延迟作为参数
Console.WriteLine("主线程继续执行...");
Console.ReadLine();
}
static void PrintNumbers()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"线程1: {i}");
Thread.Sleep(100);
}
}
static void PrintNumbersWithDelay(object delay)
{
int ms = (int)delay;
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"线程2: {i}");
Thread.Sleep(ms);
}
}
}
2. 使用ThreadPool
线程池能够管理和复用线程,从而减少线程创建和销毁所带来的开销。你可以使用QueueUserWorkItem
方法将工作项加入线程池队列。
using System;
using System.Threading;
class Program
{
static void Main()
{
// 将方法排入线程池队列执行
ThreadPool.QueueUserWorkItem(PrintNumbers);
ThreadPool.QueueUserWorkItem(PrintNumbersWithDelay, 300);
Console.WriteLine("主线程继续执行...");
Console.ReadLine();
}
static void PrintNumbers(object state)
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"线程池线程: {i}");
Thread.Sleep(100);
}
}
static void PrintNumbersWithDelay(object delay)
{
int ms = (int)delay;
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"带延迟的线程池线程: {i}");
Thread.Sleep(ms);
}
}
}
3. 使用Task Parallel Library (TPL)
借助Task
类可以创建和管理异步操作,这是.NET 4.0引入的特性,推荐优先使用这种方式。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// 使用Task.Factory.StartNew
Task task1 = Task.Factory.StartNew(PrintNumbers);
// 使用Task.Run (简化版)
Task task2 = Task.Run(() => PrintNumbersWithDelay(400));
// 带返回值的任务
Task<int> task3 = Task.Run(() => CalculateSum(10));
Console.WriteLine($"计算结果: {task3.Result}");
Console.WriteLine("主线程继续执行...");
Task.WaitAll(task1, task2); // 等待所有任务完成
Console.ReadLine();
}
static void PrintNumbers()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"任务1: {i}");
Thread.Sleep(100);
}
}
static void PrintNumbersWithDelay(int delay)
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"任务2: {i}");
Thread.Sleep(delay);
}
}
static int CalculateSum(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += i;
Thread.Sleep(50);
}
return sum;
}
}
4. 使用async/await关键字
async
和await
关键字是.NET 4.5引入的语法糖,它基于TPL构建,能够让异步代码看起来更像同步代码。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
Console.WriteLine("主线程开始...");
// 启动异步任务
Task task1 = PrintNumbersAsync();
Task<int> task2 = CalculateSumAsync(15);
// 等待任务完成
await task1;
Console.WriteLine($"计算结果: {await task2}");
Console.WriteLine("主线程结束.");
Console.ReadLine();
}
static async Task PrintNumbersAsync()
{
await Task.Run(() =>
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"异步任务: {i}");
Thread.Sleep(200);
}
});
}
static async Task<int> CalculateSumAsync(int n)
{
return await Task.Run(() =>
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += i;
Thread.Sleep(100);
}
return sum;
});
}
}
5. 使用BackgroundWorker组件(Windows Forms/WPF环境)
在Windows Forms或WPF应用程序中,可以使用BackgroundWorker
组件来执行后台操作,并且能够与UI线程进行安全通信。
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace BackgroundWorkerExample
{
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker1;
public Form1()
{
InitializeComponent();
// 初始化BackgroundWorker
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += BackgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void buttonStart_Click(object sender, EventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync(10); // 传递参数
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation)
{
backgroundWorker1.CancelAsync();
}
}
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int max = (int)e.Argument;
for (int i = 1; i <= max; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
// 执行工作
Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
e.Result = max;
}
private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// 更新UI(安全操作)
progressBar1.Value = e.ProgressPercentage;
labelStatus.Text = $"完成 {e.ProgressPercentage}%";
}
private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
labelStatus.Text = "操作已取消";
}
else if (e.Error != null)
{
labelStatus.Text = $"错误: {e.Error.Message}";
}
else
{
labelStatus.Text = $"操作完成,结果: {e.Result}";
}
}
}
}
总结
- Thread类:适合用于需要对线程进行精细控制的场景。
- ThreadPool:在执行短时间任务且需要复用线程的情况下是不错的选择。
- Task Parallel Library (TPL):推荐在大多数情况下使用,尤其是需要处理任务组合和结果的场景。
- async/await:非常适合编写异步代码,能让代码的可读性更强。
- BackgroundWorker:专门用于Windows Forms和WPF应用程序中进行后台操作并更新UI。
你可以根据具体的使用场景,挑选最合适的线程创建方式。