多线程系列1:经典卖票
Posted yusina
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程系列1:经典卖票相关的知识,希望对你有一定的参考价值。
1.卖票的方法
class TicketRest { int ticket = 1; int Max = 0; public TicketRest(int max) { Max = max; } /// <summary> /// 未加锁 /// </summary> /// <param name="num"></param> public void SellTicketNoLock(int num) { while (ticket <= Max) { if (ticket > Max) break;//这里一定要判断。 Console.WriteLine($"窗口{num}|售票员{Thread.CurrentThread.ManagedThreadId}:售出第[{ticket}]号车票,剩余{Max-ticket}张"); ticket++; Task.Delay(200); } } /// <summary> ///加锁 /// </summary> /// <param name="num"></param> public void SellTicketAddLock(int num) { while (ticket <= Max) { lock (this) { if (ticket > Max) break;//这里一定要判断。 Console.WriteLine($"窗口{num}|售票员{Thread.CurrentThread.ManagedThreadId}:售出第[{ticket}]号车票,剩余{Max - ticket}张"); ticket++; Task.Delay(200); } } }
2.使用Thred的方式调用卖票方法
未加锁的情况 (调用方法 SellTicketNoLock)会出现一张票多次卖出的情况和余票不符合的情况。
3.使用Task的方式调用卖票方法
闭包的陷阱 :
for (int i = 0; i < windowCount; i++)
{
tasklst.Add(Task.Run(() => { ticketRest2.SellTicketAddLock(i); }));
}
最后的i值都是5 而不是原来 的i值啦。
解决方法 使用临时变量,改为:
for (int i = 0; i < windowCount; i++)
{
int temp = i;
tasklst.Add(Task.Run(() => { ticketRest2.SellTicketAddLock(temp); }));
}
加锁后(SellTicketAddLock) 车票没有重复 余票也没有出错。
完整的代码:
class Program { static void Main(string[] args) { //SellThread(); SellTaskDemo(); Console.ReadLine(); } private static int ticketCount = 100;// 共20张票 private static int windowCount = 5;// 共5个窗口同时售票 /// <summary> /// //演示多线程卖票案例-Thread方式 /// </summary> static void SellThread() { try { TicketRest ticketRest = new TicketRest(ticketCount); for (int i = 0; i < windowCount; i++) { Thread thread = new Thread(() => { ticketRest.SellTicketNoLock(i); }); thread.Start(); } } catch (Exception ex) { LoggerFactory.Instance.Logger_Error(ex); Console.WriteLine($"{ex.Message}|{ex.GetType().FullName}|{ex.TargetSite}|{ex.StackTrace}"); } } /// <summary> /// 演示多线程卖票案例-Task方式 /// </summary> static void SellTaskDemo() { try { Stopwatch stopwatch1 = new Stopwatch(); stopwatch1.Start(); TicketRest ticketRest1 = new TicketRest(ticketCount); ticketRest1.SellTicketAddLock(0); stopwatch1.Stop(); Console.WriteLine($"使用单线程方式消耗时间:{stopwatch1.ElapsedMilliseconds}毫秒"); Stopwatch stopwatch2 = new Stopwatch(); stopwatch2.Start(); TicketRest ticketRest2 = new TicketRest(ticketCount); var tasklst = new List<Task>(); for (int i = 0; i < windowCount; i++) { int temp = i; tasklst.Add(Task.Run(() => { ticketRest2.SellTicketAddLock(temp); })); } Task.WaitAll(tasklst.ToArray()); stopwatch2.Stop(); Console.WriteLine($"使用多线程方式:代码段运行时间({stopwatch2.ElapsedMilliseconds}毫秒)"); } catch (Exception ex) { LoggerFactory.Instance.Logger_Error(ex); Console.WriteLine($"{ex.Message}|{ex.GetType().FullName}|{ex.TargetSite}|{ex.StackTrace}"); } } } class TicketRest { int ticket = 1; int Max = 0; public TicketRest(int max) { Max = max; } /// <summary> /// 未加锁 /// </summary> /// <param name="num"></param> public void SellTicketNoLock(int num) { while (ticket <= Max) { if (ticket > Max) break;//这里一定要判断。 Console.WriteLine($"窗口{num}|售票员{Thread.CurrentThread.ManagedThreadId}:售出第[{ticket}]号车票,剩余{Max-ticket}张"); ticket++; Task.Delay(200); } } /// <summary> ///加锁 /// </summary> /// <param name="num"></param> public void SellTicketAddLock(int num) { while (ticket <= Max) { lock (this) { if (ticket > Max) break;//这里一定要判断。 Console.WriteLine($"窗口{num}|售票员{Thread.CurrentThread.ManagedThreadId}:售出第[{ticket}]号车票,剩余{Max - ticket}张"); ticket++; // Task.Delay(200); Thread.Sleep(100); //模拟耗时操作 } } } }
LoggerFactory.Instance.Logger_Error(ex); 这是输出异常,可以使用console.writeline替代。
参考资料:
理解C#中的闭包: https://www.cnblogs.com/jiejie_peng/p/3701070.html
浅谈并发与并行(一):http://www.cnblogs.com/yangecnu/p/Something-about-Concurrent-and-Parallel-Programming.html
以上是关于多线程系列1:经典卖票的主要内容,如果未能解决你的问题,请参考以下文章