作者:何其何从丶 | 来源:互联网 | 2024-11-12 16:45
本文探讨了多线程的起源及其在现代编程中的重要性。线程的引入是为了增强进程的稳定性,确保一个进程的崩溃不会影响其他进程。而进程的存在则是为了保障操作系统的稳定运行,防止单一应用程序的错误导致整个系统的崩溃。线程作为进程的逻辑单元,多个线程共享同一CPU,需要合理调度以避免资源竞争。
线程和进程的概念源于对系统稳定性的追求。线程是为了提高进程的稳定性而设计的,一个进程的崩溃不应影响其他进程的正常运行。同样,进程的存在是为了保护操作系统的稳定性,避免一个应用程序的错误导致整个系统的崩溃。
线程是进程的逻辑单元,多个线程可以共享同一个CPU,但这也带来了资源竞争的问题。为了确保数据的一致性,操作系统会定期对线程进行调度,通常每30毫秒进行一次切换。虽然这种切换会带来一定的性能开销,但在多核处理器时代,这点性能损耗是可以接受的。
在.NET框架中,线程的实现主要通过Thread
类来完成,分为前台线程和后台线程,通过IsBackground
属性进行标记。通常情况下,我们更倾向于使用后台线程,即异步线程。线程具有优先级,高优先级的线程在调度时会被优先处理。.NET提供了丰富的线程API,如Sleep
、Join
和Abort
等。
线程池的引入旨在解决频繁创建和销毁线程带来的性能问题。线程池通过复用线程来减少这些开销。当一个线程完成任务后,它会返回线程池,等待下一次调用。例如,一个线程池中有5个线程,处理1000条数据时,每个线程可以处理200条数据。尽管线程池提高了性能,但也存在一些不足,如无法实时查看线程进度和反馈执行结果。为了解决这些问题,.NET引入了Task
类,它是在线程池基础上的进一步封装和优化,提供了更多的API,如Run
、StartFactory
、Wait
、WaitAll
和ContinueWith
等。
下面是一个简单的单线程示例:
///
/// 单线程应用
///
class Program
{
static void Main(string[] args)
{
Console.WriteLine("进入主线程");
User u = new User("小刚");
u.Getshow();
Console.WriteLine("主线程结束");
}
}
public class User
{
private string name;
public User(string name)
{
this.name = name;
}
public void Getshow()
{
Console.WriteLine("Name=>" + name);
}
}
在这个控制台程序中,只有一个由系统自动分配的主线程。程序从Main
方法开始执行,顺序控制流程。当执行到GetShow
方法时,线程会进入该方法内部执行,完成后返回Main
方法继续执行后续代码。
接下来,我们通过创建一个新的线程来执行GetShow
方法:
///
/// 多线程应用
///
class Program
{
static void Main(string[] args)
{
Console.WriteLine("进入主线程");
User u = new User("小刚");
Thread subthread = new Thread(new ThreadStart(u.Getshow)); // 创建新线程
subthread.Start(); // 开启线程
Console.WriteLine("主线程结束");
}
}
public class User
{
private string name;
public User(string name)
{
this.name = name;
}
public void Getshow()
{
Console.WriteLine("Name=>" + name);
}
}
在主线程中,我们创建了一个新的线程来执行GetShow
方法。主线程不会等待新线程完成任务,而是继续执行后续代码。这意味着主线程和新线程可以并行执行,但谁先完成是不确定的。