文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、基本概念
1)计算机基础
- 程序:为完成特定任务的一段静态的代码
- 进程:是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程,有它自身的产生,存在和消亡的过程。-------生命周期。可以从任务管理器中看到
- 线程:进程可进一步细化为线程,是一个程序内部的一条执行路径
- 并行:多个cpu同时执行多个任务。相当于多个人做不同的事
- 并发:一个cpu(采用时间片)同时执行多个任务。比如:一个人“同时”做多件事,看似是同时,其实采用时间片把每件事轮流执行一小段时间
2)多线程
- 多线程是属于操作系统的,.net平台只是提供了一个操作我们系统多线程的方式,任何的代码其实也都是这样的事,在操作系统允许的操作内操作,无创造行为。
- 任何的异步多线程都离不开委托
- 任何一个简单的程序的运行,都至少开启了一个线程,程序是执行在线程里的
- 多线程存在管理协调成本,并不是开了多少个多线程,就会有多少的性能提升
- 线程池创建线程时有上限限制,Thread原生线程无限制,随意开,但是多了之后容易死机
- 线程的启动和结束都有无序性,CPU在内部随机调配,进行分片处理
- 使用多线程时,不要试图使用延时等操作去掌控顺序,都是后续难以重现的偶尔错误来源
二、Thread
基本介绍
- NetFramwork1.0就诞生的古老多线程类
- Thread的API特别丰富,最接近操作系统的操作,但是因为线程资源是操作系统管理的,而cpu接受指令有一个随机的时间片去执行,并不好控制,响应并不灵敏
- Thread操作不慎容易造成破坏,操作也更加复杂
基本使用
这是.net最原生的操作多线程的工具类,结构如下:其中ThreadStart参数就是一个委托:public delegate void ThreadStart();
案例
public void test01()
{
Console.WriteLine("111111111111111111111");
ThreadStart s = () =>
{
Console.WriteLine("22222222222222222222222");
};
Console.WriteLine("333333333333333333333333333");
Thread thread = new Thread(s);
thread.Start();
}
结果:
111111111111111111111
333333333333333333333333333
22222222222222222222222
使用简写的方式:
public void test02()
{
Console.WriteLine("111111111111111111111");
Console.WriteLine("333333333333333333333333333");
Thread thread = new Thread(() =>
{
Console.WriteLine("22222222222222222222222");
});
thread.Start();
}
三、ThreadPool
基本介绍
- NetFramework 2.0诞生的
- ThreadPool是一种池化资源管理设计思想,用于管理线程资源,包括创建销毁等等。
- 一般当我们使用线程时,先会申请一个线程,使用完之后就释放掉;而线程池就是一个线程的容器,在使用到时,容器会提前申请几个线程,我们需要使用时,去线程池申请即可。并且对预先申请的线程状态进行控制(用一个字段表示是闲置还是使用中)
- 可以限制线程的数量,线程的复用
- API太少,线程等待顺序控制弱
基本使用
public void test03()
{
Console.WriteLine("111111111111111111111");
WaitCallback callback = o =>
{
Console.WriteLine("333333333333333333333333333");
};
ThreadPool.QueueUserWorkItem(callback);
Console.WriteLine("22222222222222222");
}
四、Parallel
基本介绍
是一个静态类,可以直接调用invoke!!!
invoke可以接受多个Action参数,用来异步执行多个方法
可以通过Parallel0ptions轻松控制最大并发数量
基本结构如下:
基本使用
public void test05()
{
Parallel.Invoke(() =>
{
Console.WriteLine("第1个线程开始执行.........");
Console.WriteLine("我的线程ID是:"+Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("第1个线程执行结束.........");
}, () =>
{
Console.WriteLine("第2个线程开始执行.........");
Console.WriteLine("我的线程ID是:" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("第2个线程执行结束.........");
}, () =>
{
Console.WriteLine("第3个线程开始执行.........");
Console.WriteLine("我的线程ID是:" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("第3个线程执行结束.........");
});
}
结果:
第1个线程开始执行.........
第2个线程开始执行.........
我的线程ID是:6
第2个线程执行结束.........
第3个线程开始执行.........
我的线程ID是:9
第3个线程执行结束.........
我的线程ID是:1
第1个线程执行结束.........
五、Task
基本介绍
- NetFramework 3.0诞生
- Task被称之为多线程的最佳实践
- Task线程全部是线程池线程
- 提供了丰富的API,适合开发实践
基本使用
创建线程
/// <summary>
/// Task创建线程
/// </summary>
public static void test01()
{
/**
* 方式一:Task
* new()->Start()
* run()
*/
//1.1 .先创建,再运行
Task task1 = new Task(() =>
{
Console.WriteLine("我是task1线程...");
});
task1.Start();
//1.2 创建时将对象返回并运行
Task task2 = Task.Run(() =>
{
Console.WriteLine("我是task2线程...");
});
Console.WriteLine(task2.Status);
/**
* 方式二:
* new TaskFactory()->StartNew()
*/
//2.1 new TaskFactory
TaskFactory fac1 = new TaskFactory();
Task task3 = fac1.StartNew(() =>
{
Console.WriteLine("我是task3线程...");
});
//2.2 获取静态对象
TaskFactory fac2 = Task.Factory;
Task task4 = fac2.StartNew(() =>
{
Console.WriteLine("我是task4线程...");
});
}
几个注意点
1)案例一:窗口应用线程的快速结束
如果我们使用窗体应用程序进行测试,注意下面的写法
public static void Main(string[] args)
{
Task.Run(() =>
{
Console.WriteLine("11111");
});
}
这种情况不会打印11111,因为在执行Main方法时,已经存在了一个窗口应用线程,当执行到第三行时,发现是异步操作,会重新创建一个线程,窗口应用线程不会停止,所以窗体应用线程结束了,第二个线程可能才执行到,因为对窗口应用线程来说,没有执行代码,速度会非常快!!!
改进,最好让窗口应用线程sleep2秒,防止窗口线程快速执行结束
public static void Main(string[] args)
{
Task.Run(() =>
{
Console.WriteLine("11111");
});
Thread.Sleep(2000);
}
2)for循环中的多线程
public void test06(