[C#] 白话C#:多线程

 白话C#:多线程

多线程是程序员面试时常常会面对的问题,对多线程概念的掌握和理解水平,也会被一些老鸟用来衡量一个人的编程实力的重要参考指标。不论是实际工作需 要还是为了应付面试,掌握多线程都是程序员职业生涯中一个必须经过的环节。其实当你把“多线程”和你的“职业生涯”联系在一起考虑的时候,就会觉得“多线 程”是多么的渺小,对,没有跨越不过的山。不过就算它很渺小,但也有可能改变你的人生轨迹。不用担心,如果你对多线程还不太熟悉,那么我们就一起来看看什 么是多线程吧。

跟前几篇的风格一样,我会在开篇的时候举一个现实生活中的例子,通过这个例子来映射一些晦涩枯燥的计算机编程专业知识,在让读者朋友很好地理解理论 概念的同时,又避免了阅读教科书时的枯燥感觉。这次我要举的例子是公司。不一定是IT公司,尽量和编程领域远一点儿吧,那就假设是一家搬家公司吧。

假如我们把公司看做是一个进程,那么人就是其中的线程。进程必须得有一个主线程,公司在创业初期往往可能出现一人打天下的现象,但是,至少得有一个 人,公司才能运作。公司创业初期,业务还不算太多,往往就是老板一个人身兼数职,一天如果只有1、2趟活儿,应该还是忙得过来的。时间长了,随着业务的发 展、口碑地建立,生意越来越兴隆,一个人肯定就忙不过来了。假设一天有5个活儿,老板一个人必须搬完A家才能搬B家,搬到黄昏估计也就搬到C家,D和E家 都还在焦急地等待着呢。老板一个人要充当搬运工、司机、业务联系人、法人代表、出纳等众多角色,累死累活公司的规模也上不去,人手不够制约了公司的发展。 那么怎么办,很简单,增加人手,用编程的话来说就是“再起个线程”。

 

我们现在就用代码来描述这样的场景吧,首先,我们准备成立一家搬家公司,于是要准备好将来和客户签的合同书:

   1:
 public
 class
 Contract
   2:
 {
   3:
     public
 string
 ID { get; private
 set; }
   4:
     public
 string
 From { get; set; }
   5:
     public
 string
 To { get; set; }
   6:
     public
 decimal
 Fee { get; set; }
   7:
  
   8:
     public
 Contract()
   9:
     {
  10:
         this
.ID = DateTime.Now.ToBinary().ToString().Replace("-"
, String.Empty);
  11:
     }
  12:
 }

 简是简单了点儿,好歹也是份合同,现在我们就去申请注册一家公司,并组建好初创团队,哪怕目前还只有老板一个人:

   1:
 public
 class
 HouseMovingCompany
   2:
 {
   3:
     private
 static
 HouseMovingCompany _instance = null
;
   4:
     public
 static
 HouseMovingCompany Instance
   5:
     {
   6:
         get { return
 (_instance == null
 ? _instance = new
 HouseMovingCompany() : _instance); }
   7:
     }
   8:
  
   9:
     public
 List<Contract> Contracts { get; private
 set; }
  10:
  
  11:
     public
 HouseMovingCompany()
  12:
     {
  13:
         this
.Contracts = new
 List<Contract>();
  14:
     }
  15:
  
  16:
     public
 void
 MoveHouse()
  17:
     {
  18:
         if
 (this
.Contracts == null
 || this
.Contracts.Count == 0)
  19:
         {
  20:
             return
;
  21:
         }
  22:
  
  23:
         Contract contract = contract = this
.Contracts[0];
  24:
         this
.Contracts.RemoveAt(0);
  25:
  
  26:
         if
 (!String.IsNullOrEmpty(contract.From) && !String.IsNullOrEmpty(contract.To))
  27:
         {
  28:
             Console.WriteLine("Move the house from {0} to {1}."
, contract.From, contract.To);
  29:
         }
  30:
  
  31:
         Thread.Sleep(5000);
  32:
     }
  33:
 }

好了,现在公司实体有了,老板就可以开始忙活了:

   1:
 static
 void
 Main(string
[] args)
   2:
 {
   3:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "WuDaokou"
, To = "LinDa Road"
, Fee = 500 });
   4:
  
   5:
     while
 (HouseMovingCompany.Instance.Contracts.Count > 0)
   6:
     {
   7:
         HouseMovingCompany.Instance.MoveHouse();
   8:
     }
   9:
 }

我们在前面设置了每次搬家耗时5秒钟,咱们把它想象成5个小时。嗯,一天接一个单子,还可以接受,但是随着老板生意日渐兴隆,有时候一天要接3个单 子,这就最少要工作15个小时了,还要操心公司的运营等问题,的确忙不过来了,而且照这样算,老板一天不可能完成5个或5个以上的单子,严重制约了公司的 发展:

   1:
 static
 void
 Main(string
[] args)
   2:
 {
   3:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "WuDaokou"
, To = "LinDa Road"
, Fee = 500 });
   4:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "XiDan"
, To = "WangFujing"
, Fee = 1000 });
   5:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "XiangShan"
, To = "The Forbidden City"
, Fee = 10000 });
   6:
  
   7:
     while
 (HouseMovingCompany.Instance.Contracts.Count > 0)
   8:
     {
   9:
         HouseMovingCompany.Instance.MoveHouse();
  10:
     }
  11:
 }

一天夜里,老板拖着疲倦的身子回到家里,一进门就一头倒在床上,他极力睁着快睁不开的眼睛,努力地对自己说:“不行,我一定要想个办法,不然我会被累死的!”。

其实办法很简单,谁都知道,招聘几个员工,再买几辆车,大家分头行动,不仅分担了工作负担,而且在规模扩大的同时还可以完成更多更大的单子。好,我们现在就借助多线程机制来实现我们的想法:

   1:
 static
 void
 Main(string
[] args)
   2:
 {
   3:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "WuDaokou"
, To = "LinDa Road"
, Fee = 500 });
   4:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "XiDan"
, To = "WangFujing"
, Fee = 1000 });
   5:
     HouseMovingCompany.Instance.Contracts.Add(new
 Contract { From = "XiangShan"
, To = "The Forbidden City"
, Fee = 10000 });
   6:
  
   7:
     Thread thread = null
;
   8:
  
   9:
     while
 (HouseMovingCompany.Instance.Contracts.Count > 0)
  10:
     {
  11:
         thread = new
 Thread(new
 ThreadStart(HouseMovingCompany.Instance.MoveHouse));
  12:
  
  13:
         thread.Start();
  14:
     }
  15:
 }

在这段程序中,我们分头行动,让每项搬家任务都由一个小团队去完成,结果我们发现,现在做三个单子的时间跟做一个单子的时间是一样的,提高了效率也扩大了公司规模。但是,既然引入了新的工作机制,我们在公司内部也不得不做一些小小的调整:

   1:
 public
 void
 MoveHouse()
   2:
 {
   3:
     if
 (this
.Contracts == null
 || this
.Contracts.Count == 0)
   4:
     {
   5:
         return
;
   6:
     }
   7:
  
   8:
     Contract contract = null
;
   9:
  
  10:
     lock
 (this
.Contracts)
  11:
     {
  12:
         contract = this
.Contracts[0];
  13:
         this
.Contracts.RemoveAt(0);
  14:
     }
  15:
  
  16:
     if
 (!String.IsNullOrEmpty(contract.From) && !String.IsNullOrEmpty(contract.To))
  17:
     {
  18:
         Console.WriteLine("Move the house from {0} to {1}."
, contract.From, contract.To);
  19:
     }
  20:
  
  21:
     Thread.Sleep(5000);
  22:
 }

调整的只是MoveHouse这个方法内部的一些实现细节。公司接到的单子都保存在Contracts中,所以搬家的时候需要去拿一个单子然后根据 单子上的信息来工作。原先我们只有一个线程在操作Contracts,倒也不觉得什么,现在有多个线程都在对Contracts中的元素进行存取,我们不 得不提防一些意外发生。这就是在使用多线程的时候常常需要考虑的并发问题,所以我们用了lock关键字,当一个线程要操作Contracts时,它先把 Contracts锁起来,其实就是声明一下:“现在我在操作它,你们谁都不要动,等我弄完了再说。”在lock块结束时被锁定的对象才会被解锁,其它的 线程现在才可以去操作它。

有了多线程机制,你会发现程序可以在更短的时间内完成更多的事情。本文没有将多线程机制中的所有概念面面俱到地列举出来,但是已经向你展示了该如何 使用多线程以及什么时候可以考虑使用多线程,其它的一些细节有待你去进一步探索,例如,你可以设置线程的优先级(假设逻辑上跟Fee挂钩,类似于‘加急 ’)等等。

掌握多线程机制,并让它使你的应用程序变得更加强悍吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值