C#线程编程实例

直接代码
        static void Main(string[] args)
        {
            SendEmailMethod(100, 2);//100个操作,2个线程
            Console.WriteLine("终于轮到老子了");
            Console.ReadLine();
        }


1、初始的SendEmailMethod方法

 public static void SendEmailMethod(int maxCount, int threadCount)
        {
            var dataList = new List<EmailSchema>();
            for (int i = 0; i < maxCount; i++)
            {
                dataList.Add(new EmailSchema { Name = "hello" + i.ToString(CultureInfo.InvariantCulture) });
            }
            //每组数量
            int groupCount = dataList.Count / threadCount;
            //余数
            int leftCount = dataList.Count % threadCount;           
            //分配给每个线程的邮件
            var emailSchemaGroups = new List<List<EmailSchema>>();
            for (int i = 0; i < threadCount; i++)
            {
                emailSchemaGroups.Add(i < leftCount
                    ? dataList.GetRange(i * (groupCount + 1), groupCount + 1)
                    : dataList.GetRange(leftCount * (groupCount + 1) + (i - leftCount) * groupCount, groupCount));
            }

            foreach (var emailSchemaGroup in emailSchemaGroups)
            {
                var thread = new Thread(m =>
                {
                    foreach (var emailData in (List<EmailSchema>)m)
                    {
                        Console.WriteLine(emailData.Name);
                    }
                }) { IsBackground = true };
                thread.Start(emailSchemaGroup);
                //子线程添加Join方法
                thread.Join();
            }
        }
 
 执行结果如下图所示: 


主线程的输出“终于轮到老子了”与子线程的输出会随机穿插出现。但是我需要让主线程输出在最后,这如何实现呢?这里考虑到Thread.Join,会阻塞调用线程,直到子线程完成位置。那么在每个子线程都调用Join方法会如何?修改代码如下:
        public static void SendEmailMethod(int maxCount, int threadCount)
        {
            var dataList = new List<EmailSchema>();
            for (int i = 0; i < maxCount; i++)
            {
                dataList.Add(new EmailSchema { Name = "hello" + i.ToString(CultureInfo.InvariantCulture) });
            }
            //每组数量
            int groupCount = dataList.Count / threadCount;
            //余数
            int leftCount = dataList.Count % threadCount;
            //分配给每个线程的邮件
            var emailSchemaGroups = new List<List<EmailSchema>>();
            for (int i = 0; i < threadCount; i++)
            {
                emailSchemaGroups.Add(i < leftCount
                    ? dataList.GetRange(i * (groupCount + 1), groupCount + 1)
                    : dataList.GetRange(leftCount * (groupCount + 1) + (i - leftCount) * groupCount, groupCount));
            }

            foreach (var emailSchemaGroup in emailSchemaGroups)
            {
                var thread = new Thread(m =>
                {
                    foreach (var emailData in (List<EmailSchema>)m)
                    {
                        Console.WriteLine(emailData.Name);
                    }
                }) { IsBackground = true };
                thread.Start(emailSchemaGroup);
                //子线程添加Join方法
                thread.Join();
            }
        }
执行结果图:

这里每次执行主线程的输出每次都会在子线程完成之后输出,但是子线程调用Join方法后,不仅仅阻止了主线程的调用,也阻止了其他子线程的调用,故此此处加了Join方法之后是相当于单线程同步执行。此方法不可行,不能达到多线程的目的。
接下来我们再次修改代码如下:
public static void SendEmailMethod(int maxCount, int threadCount)
        {
            var dataList = new List<EmailSchema>();
            for (int i = 0; i < maxCount; i++)
            {
                dataList.Add(new EmailSchema { Name = "hello" + i.ToString(CultureInfo.InvariantCulture) });
            }
            //每组数量
            int groupCount = dataList.Count / threadCount;
            //余数
            int leftCount = dataList.Count % threadCount;
            //分配给每个线程的邮件
            var emailSchemaGroups = new List<List<EmailSchema>>();
            for (int i = 0; i < threadCount; i++)
            {
                emailSchemaGroups.Add(i < leftCount
                    ? dataList.GetRange(i * (groupCount + 1), groupCount + 1)
                    : dataList.GetRange(leftCount * (groupCount + 1) + (i - leftCount) * groupCount, groupCount));
            }
            //添加线程集,用于监控线程状态
            var threads = new List<Thread>();

            foreach (var emailSchemaGroup in emailSchemaGroups)
            {
                var thread = new Thread(m =>
                {
                    foreach (var emailData in (List<EmailSchema>)m)
                    {
                        Console.WriteLine(emailData.Name);
                    }
                }) { IsBackground = true };
                thread.Start(emailSchemaGroup);
                threads.Add(thread);
            }
           //创建监控线程
            var monitor = new Thread(ThreadMonitor) { IsBackground = true };
            monitor.Start(threads);
            monitor.Join();//监控线程阻塞主线程
            monitor.DisableComObjectEagerCleanup();
        }

        /// <summary>
        /// 线程监控
        /// </summary>
        public static void ThreadMonitor(object obj)
        {
            var threads = obj as List<Thread>;
            if (threads == null) return;
            foreach (var thread in threads)
            {
                //thread.IsAlive状态等同于thread.ThreadState != ThreadState.Stopped
                while(thread.IsAlive) //遍历每个子线程,如果子线程仍然处于活跃状态,则监控线程休眠100毫秒,用于让子线程继续执行。无限循环直到子线程完成
                {
                    Thread.Sleep(100);
                }
                thread.Abort();
                thread.DisableComObjectEagerCleanup();
            }
        }
执行结果如下图:


我们创建了一个监控线程,用于监控子线程的状态,通过判断子线程的线程状态(IsAlive)判断子线程是否执行完成并杀死线程。监控线程使用Join方法来阻塞主进程,这样就得到想要的结果了。

这里监控线程的作用:
1、阻塞主线程
2、确保子线程操作完成


续:上面的线程资源分配是平均分配的,比如说我有十个需要处理的数据,那么会事先分成2组数据每组5个,分别交给2个线程。这样做可以不用考虑资源会被重复访问,但是会出现一个线程先执行完,另一个还有好几个数据没处理完,线程的利用率不是100%的。现在重新改良方法,如下:

public static void SendEmailMethod(int maxCount, int threadCount)
        {
            var dataList = new List<EmailSchema>();
            for (int i = 0; i < maxCount; i++)
            {
                dataList.Add(new EmailSchema { Name = "hello" + i.ToString(CultureInfo.InvariantCulture) });
            }
            Queue<EmailSchema> dataQueue = null; 
            if (dataList == null || dataList.Count == 0)
            {
                return;
            }
            dataQueue = new Queue<EmailSchema>(dataList);
            //线程调用
            var threads = new List<Thread>();
            for (int i = 0; i < threadCount; i++)
            {
                var thread = new Thread(m =>
                {
                    var newDataQueue = m as Queue<EmailSchema>;
                    while (newDataQueue != null && newDataQueue.Count > 0)
                    {
                        var emailData = newDataQueue.Dequeue();//线程安全的资源,移除并返回栈中第一个对象
                        SendEmailByData(emailData);
                    }
                }) { IsBackground = true };
                thread.Start(dataQueue);
                threads.Add(thread);
            }

            //线程监控
            var monitor = new Thread(ThreadMonitor) { IsBackground = true };
            monitor.Start(threads);
            monitor.Join();
            monitor.DisableComObjectEagerCleanup();
        }


这里用到了泛型类Queue<>解决资源分配不均匀问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值