进程和线程
打开任务管理器可以看到正在运行的进程。
进程是什么?
对于用户来说:进程是程序的一次动态执行过程
对于操作系统来说:进程是操作系统分配资源的基本单位,也是最小单位
为什么会有进程?
CPU一次只能处理一个程序,CPU速度很快,而内存很慢,所以CPU会有大量的时间都是空闲的。而CPU又是很昂贵的,为了解决浪费CPU的情况,就出现了中断处理,将程序分成一小片一小片的,这个进程执行一点,那个进程执行一点。虽然在内部进程的执行是一段一段的,但是CPU的速度很快的(速度都是纳秒级别的),所以我们是感受不到进程执行过程中的停顿的。
在操作系统中引入进程,是为了实现多个程序的并发执行。传统的程序不能与其他程序并发执行,只有在为之创建进程后,才能与其他程序(进程)并发执行。
线程
线程(Thread)是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。
多线程
多线程的优点
可以同时完成多个任务;可以使程序的响应速度更快;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;可以随时停止任务;可以设置每个任务的优先级以优化程序性能。
多线程的缺点
线程也是程序,所以线程需要占用内存,线程越多,占用内存也越多。
多线程需要协调和管理,所以需要占用CPU时间以便跟踪线程。
线程之间对共享资源的访问会相互影响,必须解决争用共享资源的问题。
线程太多会导致控制太复杂,最终可能造成很多程序缺陷。
创建线程执行无参委托
public delegate void ThreadStart()
静态方法
/// <summary>无参的方法</summary> static void Func1() { Console.WriteLine("这是无参的方法"); } Thread thread = new Thread(new ThreadStart(Func1)); //调用Start方法执行线程 thread.Start(); Console.ReadKey();
实例方法
Thread thread = new Thread(new ThreadStart(new TestClass().Func1)); //调用Start方法执行线程 thread.Start(); Console.ReadKey(); class TestClass { /// <summary>无参的方法</summary> public void Func1() { Console.WriteLine("这是无参的实例方法"); } }
匿名方法和Lambda表达式
Thread thread1 = new Thread(delegate () { Console.WriteLine("匿名委托"); }); Thread thread2 = new Thread(()=> { Console.WriteLine("Lambda表达式"); }); thread1.Start(); thread2.Start(); Console.ReadKey();
这里发现Lambda反而先执行是因为开了两个线程同时执行的。
创建线程执行有参数的委托
public delegate void ParameterizedThreadStart(Object obj)
ParameterizedThreadStart委托的参数类型必须是Object的。
//通过ParameterizedThreadStart创建线程 Thread thread = new Thread(new ParameterizedThreadStart(Func1)); //给方法传值 thread.Start("这是一个有参数的委托"); Console.ReadKey(); /// <summary> /// 创建有参的方法 /// 注意:方法里面的参数类型必须是Object类型 /// </summary> /// <param name="obj"></param> static void Func1(object obj) { Console.WriteLine(obj); }
线程的属性
//获取正在运行的线程 Thread thread = Thread.CurrentThread; //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; Thread thread2 = new Thread(() => { Console.WriteLine("111"); }); Console.WriteLine($"主线程ID:{id}"); Console.WriteLine($"主线程状态:{state}"); Console.WriteLine($"主线程优先级:{priority}"); Console.WriteLine($"thread2 ID:{thread2.ManagedThreadId}"); Console.WriteLine($"thread2 状态:{thread2.ThreadState}"); Console.WriteLine($"thread2 优先级:{thread2.Priority}"); thread2.Start(); Console.WriteLine($"thread2 状态:{thread2.ThreadState}"); Console.ReadKey();
前台线程和后台线程
介绍
前台线程:只有所有的前台线程都结束,应用程序才能结束。默认情况下创建的线程都是前台线程
后台线程:只要所有的前台线程结束,后台线程自动结束。通过Thread.IsBackground设置后台线程。必须在调用Start方法之前设置线程的类型,否则一旦线程运行,将无法改变其类型。
通过BeginXXX方法运行的线程都是后台线程。
使用
//演示前台、后台线程 TestClass f = new TestClass(10); //创建前台线程 Thread fThread = new Thread(new ThreadStart(f.RunLoop)); //给线程命名 fThread.Name = "前台线程"; TestClass b = new TestClass(20); //创建后台线程 Thread bThread = new Thread(new ThreadStart(b.RunLoop)); bThread.Name = "后台线程"; //设置为后台线程 bThread.IsBackground = true; //启动线程 fThread.Start(); bThread.Start(); class TestClass { private int Count; public TestClass(int count) { this.Count = count; } public void RunLoop() { //获取当前线程的名称 string threadName = Thread.CurrentThread.Name; for (int i = 0; i < Count; i++) { Console.WriteLine($"{threadName}计数:{i}"); //线程休眠500毫秒 Thread.Sleep(1000); } Console.WriteLine("{0}完成计数", threadName); } }
我们发现前台线程执行完了不等待后台线程执行完控制台程序就结束了。
我们给bThread不设置为后台线程再输出看看:
线程同步
是指在某一时刻只有一个线程可以访问变量。
lock(expression) { statement_block }
expression代表你希望跟踪的对象:
如果你想保护一个类的实例,一般地,你可以使用this;
如果你想保护一个静态变量(如互斥代码段在一个静态方法内部),一般使用类名就可以了
而statement_block就算互斥段的代码,这段代码在一个时刻内只可能被一个线程执行。
抢红包的案例(发了三个包)
RedBao red = new RedBao(); //五个人同时抢 Thread t1 = new Thread(new ThreadStart(red.Qiang)); Thread t2 = new Thread(new ThreadStart(red.Qiang)); Thread t3 = new Thread(new ThreadStart(red.Qiang)); Thread t4 = new Thread(new ThreadStart(red.Qiang)); Thread t5 = new Thread(new ThreadStart(red.Qiang)); //启动线程 t1.Start(); t2.Start(); t3.Start(); t4.Start(); t5.Start(); Console.ReadKey(); class RedBao { public int count = 3; public void Qiang() { int temp = count; if (temp > 0)//判断是否还有库存 { Thread.Sleep(1000); count -= 1; Console.WriteLine("恭喜你抢到了0.01元"); } else { Console.WriteLine("太慢了,红包已被抢光"); } } }
发了三个抢走了五个肯定有问题,我们加上线程同步来解决(修改下Qiang方法):
public void Qiang() { lock (this) { int temp = count; if (temp > 0)//判断是否还有库存 { Thread.Sleep(1000); count -= 1; Console.WriteLine("恭喜你抢到了0.01元"); } else { Console.WriteLine("太慢了,红包已被抢光"); } } }
原文:https://www.cnblogs.com/dotnet261010/p/6159984.html