一直没有系统学习过C# 的多线程,今天跑一个图片迁移的小程序时,发现速度奇慢,想着要是改成多线程的应该就会好很多,但是改造过程总是出现奇奇怪怪的错误,怪只怪基础没打好,下决心要从基础开始了解多线程。
1.多线程实现方式private void btnThreadTest_Click(object sender, EventArgs e) {
try
{
// CreatThreadByNewThread();
// CreatThreadByThreadPool();
CreatThreadByTask();
CreatThreadByDelegate();
for (var i = 0; i < 10000; i++)
{
Console.Write(i + "x");
}
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 直接new一个Thread
/// </summary>
public void CreatThreadByNewThread() {
try
{
//1.直接new一个新线程
//Thread firstThread = new Thread(new ThreadStart(ThreadTest1));//无参线程
Thread firstThread = new Thread(new ParameterizedThreadStart(ThreadTest1));
firstThread.Start("线程参数");
firstThread.Join();//同下文中task的wait
Thread.Sleep(1);//暂停当前线程一段时间,单位微秒 ,Thread.Sleep(0)立即放弃这个线程的时间片,主动交出CPU给其他线程
}
catch (Exception)
{
throw;
}
}
//使用线程池
public void CreatThreadByThreadPool() {
try
{
//2.线程池
ThreadPool.UnsafeQueueUserWorkItem(ThreadTest1, "线程参数");
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 使用task
/// </summary>
public void CreatThreadByTask()
{
try
{
//3.task执行
Task<int> t1 = new Task<int>(n => ThreadTest2((object)n), "线程参数");
t1.Start();
t1.Wait();//等待线程执行完成
Task tend = t1.ContinueWith(task => Console.WriteLine("Thread result is {0}", t1.Result));
}
catch (Exception)
{
throw;
}
}
//使用委托异步执行 public void CreatThreadByDelegate() { try { //4. 委托异步执行,委托有多种声明方 //Delegate 至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型 //Func可以接受0个至16个传入参数,必须具有返回值 func<string,int> fun_t=ThreadTest2 //Action可以接受0个至16个传入参数,无返回值 //Predicate只能接受一个传入参数,返回值为bool类型 MyDelegate mydelegate = new MyDelegate(ThreadTest2); IAsyncResult result = mydelegate.BeginInvoke("线程执行参数", ThreadCallback, "线程回调参数");//线程执行完成后自动执行的回调函数 int resstr = mydelegate.EndInvoke(result);//会等待线程执行完成后执行 Console.WriteLine("Thread result is {0}", resstr); } catch (Exception) { throw; } }
2.多线程数据安全。
对于多线程共享的数据,且有线程对共享数据存在写操作时,需要添加独占锁,lock,将线程对改共享数据操作部分加锁,下面中done就是共享数据
static readonly object locker = new object(); lock (locker) { if (!done) { Console.WriteLine("Done"); done = true; } }
当某一个线程访问独占锁时,其他线程会阻塞等待,独占锁的释放,
有一个批量下载上传的任务,当使用到上面介绍的线程池来做上传处理时,发现如果不对线程池做控制,则很可能出现死锁的情况,线程池中一部分线程都阻塞在IO上,因此设置线程池线程的数量
ThreadPool.SetMinThreads(2, 1);//参数1:线程池根据需要穿件的新的最小工作程序线城市数,参数2:新的最小空闲异步I/O线程数 ThreadPool.SetMaxThreads(5, 10);//第一个参数是线程池中辅助线程的最大数目,第二个参数是线程池中异步I/O线程的最大数目
下面的方法能够查询到还有多少线程在运行,适合于查询是否有线程死锁
//检索由 System.Threading.ThreadPool.GetMaxThreads(System.Int32@,System.Int32@) 方法返回的最大线程池线程数和当前活动线程数之间的差值。 //参数: //workerThreads: //可用辅助线程的数目。 //completionPortThreads: //可用异步 I/O 线程的数目。 ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); //检索由 System.Threading.ThreadPool.GetMaxThreads(System.Int32@,System.Int32@) 方法返回的最大线程池线程数和当前活动线程数之间的差值。 // 参数: //workerThreads: //可用辅助线程的数目。 //completionPortThreads: //可用异步 I/O 线程的数目。 ThreadPool.GetMaxThreads(out maxWordThreads, out completionPortThreads);