C#多线程--仓库问题引发的故事
假设有这么个场景,一个仓库,里面有N件货物,现有六个搬运工(用线程模拟),其中2个向仓库放东西,4个往外搬东西。假设1秒能向里放2件货物,同时可向外搬3件货物(线程休眠),现在需要往里放M件货物,一旦仓库有货就要向外搬,这个东西怎么设计?
这显然牵扯到线程同步的问题。本来,考虑的有点简单了,只用了一个锁,但结果是在执行一个动作的同时,另一个动作一直在等待(比如,放的时候,搬的线程等待放完后,才能开始运行),也就是在一秒内,只能放或者搬,这样的话,还不如一个线程全跑下来了,还省事。思考良久后,请教了一下,原来这种问题要放两个线程锁(对应两个动作),恍然大悟。好了,别的不说了,直接上这货的代码吧:假设N和M都为15,标准情况下需要放一个队列,现在只用最简单的数字来模拟吧
class Operator { static int pushNum = 20; static int num = 20; private object locker1 = new object();//这个锁负责往里放 private object locker2 = new object();//这个锁负责往外拿 public int Total { get { return num; } } public int PushTotal { get { return pushNum ; } } public void setPushNum(int t) { pushNum = t; lock (locker1) { Monitor.PulseAll(locker1); } } public void Push() { while (1 == 1) { lock (locker1) { if (pushNum <= 0) { try { Monitor.Wait(locker1); } catch (SynchronizationLockException e) { Console.WriteLine(e); } catch (ThreadInterruptedException e) { Console.WriteLine(e); } } else { Thread.Sleep(500); pushNum--; num++; Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("放入一件商品,此时还剩数量:{0},\t还需要放的数量:{1},\t搬运工:{2}", num, pushNum,
Thread.CurrentThread.Name); lock (locker2) { Monitor.PulseAll(locker2); } } } } } public void Pull() { while (1 == 1) { lock (locker2) { if (num <= 0) { try { Monitor.Wait(locker2); } catch (SynchronizationLockException e) { Console.WriteLine(e); } catch (ThreadInterruptedException e) { Console.WriteLine(e); } } else { Thread.Sleep(333); num--; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("搬出一件商品,此时还剩商品数:{0}\t搬运工:{1}",num , Thread.CurrentThread.Name); } } } } }
上面的红色字体显示了两个线程锁,以及激活其他线程的时间段,下面贴上主线程:
static void Main(string[] args) { Operator op=new Operator(); Random r=new Random(); Thread thread1 = new Thread(new ThreadStart(op.Push)); thread1.Name = "push[1]"; Thread thread2 = new Thread(new ThreadStart(op.Push)); thread2.Name = "push[2]"; //Thread thread3 = new Thread(new ThreadStart(op.Push)); //thread3.Name = "push[3]"; //Thread thread4 = new Thread(new ThreadStart(op.Push)); //thread4.Name = "push[4]"; Thread thread11 = new Thread(new ThreadStart(op.Pull)); thread11.Name = "pull[1]"; Thread thread12 = new Thread(new ThreadStart(op.Pull)); thread12.Name = "pull[2]"; Thread thread13 = new Thread(new ThreadStart(op.Pull)); thread13.Name = "pull[3]"; Thread thread14 = new Thread(new ThreadStart(op.Pull)); thread14.Name = "pull[4]"; try { thread1.Start(); thread2.Start(); //thread3.Start(); //thread4.Start(); thread11.Start(); thread12.Start(); thread13.Start(); thread14.Start(); do { if (op.Total == 0&&op.PushTotal==0) { Console.WriteLine("是否继续放入 Y/N"); while (Console.ReadLine().ToUpper() == "Y") { Console.WriteLine("输入数量:"); int t; Int32.TryParse(Console.ReadLine(), out t); op.setPushNum(t); } } else { Thread.Sleep(1000); } } while (true); } catch (ThreadStateException e) { Console.WriteLine(e); } catch (ThreadInterruptedException e) { Console.WriteLine(e); } }
效果图如下:
当按下y后,继续激活等待的线程:
浮躁的人容易问:我到底该学什么;----别问,学就对了; 浮躁的人容易问:JS有钱途吗;----建议你去抢银行; 浮躁的人容易说:我要中文版!我英文不行!----不行?学呀! 浮躁的人分两种:只观望而不学的人;只学而不坚持的人; 浮躁的人永远不是一个高手。