• C#中一道关于线程同步的练习题——模拟多窗口售票


    题目:模拟窗口卖票,四个窗口同时对外开放售票,需要按顺序售出。

    要求:输出每一张票的售出时间和售出窗口,不能出现票未售出或者被售出多次的情况。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.IO;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace SellTicketsSynchronously
    {
        class Program
        {
            //入口
            static void Main(string[] args)
            {
                Ticket tc = new Ticket(10);
                Thread sellWindowA = new Thread(new ParameterizedThreadStart(SellTicket));
                Thread sellWindowB = new Thread(new ParameterizedThreadStart(SellTicket));
                Thread sellWindowC = new Thread(new ParameterizedThreadStart(SellTicket));
                Thread sellWindowD = new Thread(new ParameterizedThreadStart(SellTicket));
                sellWindowA.Name = "Window A";
                sellWindowB.Name = "Window B";
                sellWindowC.Name = "Window C";
                sellWindowD.Name = "Window D";
                sellWindowA.Start(tc);
                sellWindowB.Start(tc);
                sellWindowC.Start(tc);
                sellWindowD.Start(tc);
                sellWindowA.Join();
                sellWindowB.Join();
                sellWindowC.Join();
                sellWindowD.Join();
                Console.WriteLine("Tickets has been sold out. Press any key to quit:");
                Console.ReadLine();
            }
            //卖票方法
            public static void SellTicket(object obj) 
            {
                Ticket ticket = obj as Ticket;
                while (ticket.NumOfTickets>0)
                {
                    lock (ticket)
                    {
                        if (ticket.NumOfTickets > 0)
                        {
                            try
                            {
                                ticket.NumOfTickets--;
                                Console.WriteLine( DateTime.Now.ToString()+":"+Thread.CurrentThread.Name + " sells a ticket, " + ticket.NumOfTickets + " tickets left.");
                            }
                            catch (Exception ex)
                            {
                                WriteLog(ex);
                            }
                        }
                    }
                    Random random = new Random();
                    Thread.Sleep(random.Next(100,500));
                } 
            }
            //打log方法
            private static void WriteLog(Exception ex)
            {
                string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\SellTicketslog.txt";
                if (File.Exists(@logUrl))
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
            }
        }
        //票类
        class Ticket 
        {
            public int NumOfTickets { get; set; }
            public Ticket(int num) 
            {
                this.NumOfTickets = num;
            }
        }
    }

    运行结果:

    不知道这么写会不会有问题,求指点。

    ————————修改版——————————

    经过园友指点,我改用了Task写了这段代码,其间得到了园友的帮助,非常感谢!

    修改后的代码如下(蓝色字体为修改的部分):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.IO;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace SellTicketsSynchronously
    {
        class Program
        {
            //入口
            static void Main(string[] args)
            {
                Ticket tc = new Ticket(10);
                WaitForAllSales(tc);
                Console.WriteLine("Tickets has been sold out. Press any key to quit:");
                Console.ReadLine();
            }
            //售罄方法
            private static void WaitForAllSales(Ticket tc) 
            {
                //创建一个Task类型的泛型list
                List<Task> tasks = new List<Task>();
                for (int i = 1; i <= 4; i++)
                {
                    //将所有的售票task存入list
                    tasks.Add(Task.Run(() => { SellTicket(string.Format("Window"+i), tc); }));
                }
                //等待所有的task都完成
                Task.WaitAll(tasks.ToArray());
            }
            //卖票方法
            public static void SellTicket(string windowName, object obj) 
            {
                string nameOfWindow = windowName;
                Ticket ticket = obj as Ticket;
                while (ticket.NumOfTickets > 0)
                {
                    lock (ticket)
                    {
                        if (ticket.NumOfTickets > 0)
                        {
                            try
                            {
                                ticket.NumOfTickets--;
                                Console.WriteLine(DateTime.Now.ToString() + ":" + nameOfWindow + " sells a ticket, " + ticket.NumOfTickets + " tickets left.");
                            }
                            catch (Exception ex)
                            {
                                WriteLog(ex);
                            }
                        }
                    }
                    Random random = new Random();
                    Thread.Sleep(random.Next(100,500));
                }
            }
            //打log方法
            private static void WriteLog(Exception ex)
            {
                string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\SellTicketslog.txt";
                if (File.Exists(@logUrl))
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
            }
        }
        //票类
        class Ticket 
        {
            public int NumOfTickets { get; set; }
            public Ticket(int num) 
            {
                this.NumOfTickets = num;
            }
        }
    }

    运行结果:

    欢迎大家发散思维,继续提出宝贵意见!:)

     ------------------------------------------------------------------------------------------------------------

    经过一位朋友细心的发现,上面这个程序逻辑是有问题的,一直都是售票窗口5在售票,修改后的代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.IO;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace SellTicketsSynchronously
    {
        class Program
        {
            //入口
            static void Main(string[] args)
            {
                Ticket tc = new Ticket(20);
                WaitForAllSales(tc);       
                Console.ReadLine();
            }
            //售罄方法
            private static void WaitForAllSales(Ticket tc) 
            {
                //创建一个Task类型的泛型list
                List<Task> tasks = new List<Task>();
                System.Random ran = new Random();
                while (tc.NumOfTickets > 0)
                {
                    int i = ran.Next(1,6);
                    //将所有的售票task存入list
                    tasks.Add(Task.Run(() => { SellTicket(string.Format("Window" + i), tc); }));
                    Task.WaitAll(tasks.ToArray());
                }
                Console.WriteLine("Tickets has been sold out. Press any key to quit:");
            }
            //卖票方法
            public static void SellTicket(string windowName, object obj) 
            {
                string nameOfWindow = windowName;
                Ticket ticket = obj as Ticket;
                lock (ticket)
                {
                    if (ticket.NumOfTickets > 0)
                    {
                        try
                        {
                            ticket.NumOfTickets--;
                            Console.WriteLine(DateTime.Now.ToString() + ":" + nameOfWindow + " sells a ticket, " + ticket.NumOfTickets + " tickets left.");
                        }
                        catch (Exception ex)
                        {
                            WriteLog(ex);
                        }
                    }
                    Random random = new Random();
                    Thread.Sleep(random.Next(100,500));
                }
            }
            //打log方法
            private static void WriteLog(Exception ex)
            {
                string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\SellTicketslog.txt";
                if (File.Exists(@logUrl))
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.Append))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                        {
                            try
                            {
                                sw.Write(ex);
                            }
                            catch (Exception ex1)
                            {
                                WriteLog(ex1);
                            }
                            finally
                            {
                                sw.Close();
                                fs.Close();
                            }
                        }
                    }
                }
            }
        }
        //票类
        class Ticket 
        {
            public int NumOfTickets { get; set; }
            public Ticket(int num) 
            {
                this.NumOfTickets = num;
            }
        }
    }

    本次修改了售罄方法和入口方法(橙色字体),运行结果如下:

    欢迎继续提出意见!谢谢大家~

  • 相关阅读:
    CAS简介
    Volatile的3大特性
    dsf对矩阵进行搜索
    JVM
    REST风格
    自定义Starters(自动配置Bean)
    反射和注解的原理
    mybatis的注解开发
    Java的多线程安全
    mybatis(3)
  • 原文地址:https://www.cnblogs.com/LanTianYou/p/4578776.html
Copyright © 2020-2023  润新知