zoukankan      html  css  js  c++  java
  • 多线程系列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);
                    }
                }
            }
    View Code

    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); //模拟耗时操作
                    }
                }
            }
        }
    View Code

    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

  • 相关阅读:
    【Python】异常
    【Python】面向对象
    【Python】文件操作
    【Python】函数
    【Python】介绍以及环境搭建
    【Java】阿里巴巴开发规范手册
    【Java】NIO
    【Java】JUC
    【Git】国内的项目托管网站-码云
    【Git】在 Idea 中使用 Git
  • 原文地址:https://www.cnblogs.com/wtujvk/p/8859095.html
Copyright © 2011-2022 走看看