线程和进程:
一个应用程序启动,会启动一个进程(应用程序运行的载体),然后进程启动多个线程。
使用Thread类创建和控制线程。
Thread thread = new Thread(Test);
thread.start();
class Program
{
public void Test()
{
Console.WriteLine("Test start....");
Thread.Sleep(1000);
Console.WriteLine("Test complet....");
}
static void Main(string[] args)
{
/*Program program = new Program();
program.Test();*/
Thread thread = new Thread(new Program().Test);//如果Test方法是静态的:Thread thread = new Thread(Test);
thread.Start();
Console.WriteLine("Main start....");
Console.WriteLine("Main complet....");
}
}
获取线程id的方法:Thread.CurrentThread.ManagedThreadId
往线程里面去传递参数
使用thread.Start()
可以传递无参的委托类型和有参的委托类型
传递一个数据:
static void DownLoad(Object obj)
{
string str = obj as string; //使用as做类型转换,转换成功直接返回,转换不成功就会返回null.
Console.WriteLine(str);
}
static void Main(string[] args)
{
Thread thread = new Thread(DownLoad);
thread.Start("http://www.google.com/xx/xxx/xx.mp4"); //直接把该字符串传递给DownLoad方法。
Console.WriteLine("Main complet...." + Thread.CurrentThread.ManagedThreadId);
}
传递多个数据:
定义一个结构体:public struct Data{//定义需要传递的数据}
class Program
{
public struct Data //结构体里声明需要传递的数据
{
public string name;
public int age;
public string massage;
}
static void DownLoad(Object obj)
{
Data data = (Data)obj;//结构体是值类型,不能使用as转换,只能使用强制转换
Console.WriteLine("姓名:"+data.name+"年龄:"+data.age+"信息:"+data.massage);
}
static void Main(string[] args)
{
//定义需要传递的数据
Data data = new Data();
data.name = "张三";
data.age = 12;
data.massage = "new person";
Thread thread = new Thread(DownLoad);
thread.Start(data);
}
}
自定义类传递数据
后台线程和前台线程,一般用Thread创建的线程都是前台线程,后台线程操作:
var thread = new Thread(Test) {IsBackground = false}; //默认为前台线程(当主线程结束后,但子线程没有结束,会等所有的线程结束后该前台线程才结束)
var thread = new Thread(Test) {IsBackground = true}; //默认为后台线程(当主线程结束后,不论子线程结束与否,后台线程都会关闭)
线程的优先级
5个优先等级:Highest,AboveNormal,Normal,BelowNormal,Lowest
Thread a= new Thread(A);
a.Priority = ThreadPriority.Highest;
线程有5种状态:
新建(new Thread)、就绪(runnable),运行(running)、阻塞(blocked)、结束(dead)
线程池
线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。
从线程池中取出线程:ThreadPool.QueueUserWorkItem(Download);
1)线程池中的所有线程都是后台线程。如果进程的所有前台线程都结束了,所有的后台线程就会停止。不能把入池的线程改为前台线程;
2)不能给入池的线程设置优先级或者名称;
3)入池的线程只能用于时间较短的任务,如果线程要一直运行(如:word的拼写检查器线程),就应该使用Thread类创建一个线程。
任务
创建任务:
1)TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.StartNew(Test);
2)Task task1 = new Task(Test);
task1.Start();
连续任务:
task1.ContinueWith(Second);
static void First()
{
Console.WriteLine("第一步");
Thread.Sleep(2000);
}
static void Second(Task task)
{
Console.WriteLine("第二步");
}
static void Main(string[] args)
{
Task task1 = new Task(First);
Task task2 = task1.ContinueWith(Second);
task1.Start();
Thread.Sleep(3000);
}
资源访问冲突
class States
{
private int state = 5;
public void StateChange()
{
if (state == 5)
{
state++;
Console.WriteLine("state = :" + state + " 该线程为:" + Thread.CurrentThread.ManagedThreadId);
}
state = 5;
}
}
class Program
{
static void Main(string[] args)
{
States states = new States();
for(int i = 0; i < 20; i++)
{
Thread thread = new Thread(states.StateChange);
thread.Start();
}
}
}
state = :6 该线程为:5
state = :5 该线程为:8
state = :5 该线程为:6
state = :6 该线程为:9
state = :6 该线程为:12
state = :6 该线程为:15
运行结果有些获得的状态为5,有的为6。原因是当某一线程执行到StateChange()方法中的打印语句行时,在它前面运行的线程已经执行将“state=5”语句执行完了,等于说state的值从5变成了6再次变成了5,因此,该线程打印出来的state=5。
使用锁机制可解决资源访问冲突。
锁的定义:private Object _lock = new Object();
锁的使用:锁只能被一个线程拿到,其他线程只能等待,锁使用完后,释放,其他线程抢占。
class States
{
private int state = 5;
private Object _lock = new object();
public void StateChange()
{
lock (_lock)
{
if (state == 5)
{
state++;
Console.WriteLine("state = :" + state + " 该线程为:" + Thread.CurrentThread.ManagedThreadId);
}
state = 5;
}
}
}
锁的好处:这段代码在同一时间只能被一个进程执行。
缺点:会拖慢多线程的执行速度。
多线程的死锁问题
有一把叉子和一把刀子,同时拿到叉子和刀子才能吃饭,
设计两个锁,分别对应叉子和刀子,
当线程拿了叉子的锁,同时也要拿刀子的锁才可以。否则会发生死锁:一个线程拿了叉子,去拿刀子时发现其他线程已经占用,则等待其他线程释放,而其他拿了刀子的线程也在等该线程释放叉子锁,两个线程都在等待对方释放锁。导致程序无法往下运行,造成死锁。
解决方法,设计取锁的先后顺序:先拿叉子再拿刀子
lock(_lock1){lock(_lock2){}}
class States
{
private int state1 = 5;
private int state2 = 5;
private Object _lock1 = new object();
private Object _lock2 = new object();
public void StateChange()
{
lock (_lock1)
{
Console.WriteLine("该线程为:" + Thread.CurrentThread.ManagedThreadId+"拿到了第1把锁");
lock (_lock2)
{
Console.WriteLine("该线程为:" + Thread.CurrentThread.ManagedThreadId + "拿到了第2把锁");
if (state1 == 5)
{
state1++;
Console.WriteLine("state = :" + state1 + " 该线程为:" + Thread.CurrentThread.ManagedThreadId);
}
state1 = 5;
if (state2 == 5)
{
state2++;
Console.WriteLine("state = :" + state2 + " 该线程为:" + Thread.CurrentThread.ManagedThreadId);
}
state2 = 5;
}
}
}
}
标签:Console,Thread,state,线程,WriteLine,new
From: https://www.cnblogs.com/Joyce-mi7/p/16922380.html