• 多线程编程学习笔记-基础(三)


    接上文 多线程编程学习笔记-基础(一)

    接上文 多线程编程学习笔记-基础(二)

    九、向线程传递参数

     1.代码如下。

    using System;
    
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading; //引入线程
    using System.Diagnostics;
     
    
    namespace ThreadConsoleApp
    {
    
        class Program
        {
            static void Main(string[] args)
            {
    
                Console.WriteLine("开始,给线程传参数");          
    
                var fore = new ThreadBackground(10);   
    
                Thread t = new Thread(fore.CountNumber);
                t.Name = "线程1";         
    
                //启动线程
    
                t.Start();
                t.Join();
                Console.WriteLine("----------------------------"); 
    
                var t2 = new Thread(Count);
                t2.Name = "线程2";
                t2.Start(8);
                t2.Join();
                Console.WriteLine("----------------------------"); 
    
                var t3 = new Thread(()=>CountNumber(12));
                t3.Name = "线程3";
                t3.Start();
                t3.Join();
                Console.WriteLine("----------------------------");
    
     
    
                int i = 10;
                var t4 = new Thread(() => PrintNumber(i));
                t4.Name = "线程4";
                i = 20;
                var t5 = new Thread(() => PrintNumber(i));
                t5.Name = "线程5";
                t4.Start();
                t5.Start();
                Console.Read();
            }
    
            static void CountNumber(int cnt)
            {
                for (int i = 0; i < cnt; i++)
                {
    
                    Thread.Sleep(500);
                    Console.WriteLine(string.Format(" {0}    打印 {1,11} 数字", Thread.CurrentThread.Name, i.ToString("N0")));
    
                }
    
            }
    
            static void Count(object cnt)
            {
                CountNumber((int)cnt);
            }
            static void PrintNumber(int num)
            {        
    
                Console.WriteLine(string.Format(" {0} 打印 {1,11} 数字", Thread.CurrentThread.Name, num.ToString("N0")));         
    
            } 
        }
    }
    
     

     2.结果如下图。

     

    线程1,我们通过实例化对象来进行参数传递。

    线程2,我们使用Thread.Start()来传递参数,不过此方法只接收单个参数,而且是对象类型。

    线程3,我们使用lambda表达式进行参数传递,lambda表达式定义了一个不属于任何类的方法,同时该方法调用了我们实际要执行的方法,同时传递参数给线程。

    线程4与线程5,则是显示了使用lambda表达式进行参数传递的一个问题,即当多个lambda表达式共用一个变量时,它们会共享这个变量的值。如图中线程4与线程5所显示,没有打印10,只打印了20。

     

    十、使用lock锁定操作

     1.代码如下

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading; //引入线程
    using System.Diagnostics;
     
    
    namespace ThreadConsoleApp
    {
        class Program
        {
    
            static void Main(string[] args)
            {
                Console.WriteLine("开始,给线程加锁");           
    
                var c = new Counter();           
    
                Thread t = new Thread(()=>Count(c));
                var t3 = new Thread(() => Count(c));
    
                 var t2 = new Thread(() => Count(c));
                t.Name = "线程1";         
    
                //启动线程
                t.Start();
             
    
                t2.Name = "线程2";
                t2.Start();     
     
                t3.Name = "线程3";
                t3.Start();
                t.Join();
                t2.Join();     
                t3.Join();
                Console.WriteLine(string.Format("没有加锁的多线程总计:{0}",c.Count));
                Console.WriteLine("----------------------------");
    
    
                var c1 = new CounterLock();
                var t4 = new Thread(() => Count(c1));
                t4.Name = "线程4";
               
    
                var t5 = new Thread(() => Count(c1));
                t5.Name = "线程5";
                var t6 = new Thread(() => Count(c1));
                t6.Name = "线程6";
    
                t4.Start();
                t5.Start();
                t6.Start();
                t4.Join();
                t5.Join();
                t6.Join();
                Console.WriteLine(string.Format("加锁的多线程总计:{0}", c1.Count));
                Console.Read();
            }      
    
            static void Count(CountBase cnt)
            {
                for (int i = 0; i < 100000; i++)
                {
                    cnt.Incerement();
                    cnt.Dncerement();
    
                }
            }
         }
    
        abstract class CountBase
        {
             public abstract void  Incerement();
            public abstract void Dncerement();
        }
    
        class Counter : CountBase
        {
            public int Count { get; private set; }
            public override void Dncerement()
            {
                Count--;
            }
    
            public override void Incerement()
            {
    
                Count++;
            }
        }
    
        class CounterLock : CountBase
        {
            private readonly object objSync = new object();
            public int Count { get; private set; }
            public override void Dncerement()
            {
                lock (objSync)
                {
                    Count--;
                }       
            }
    
            public override void Incerement()
            {
                lock (objSync)
                {
                    Count++;
                }
            }
        }
    
    }
    
     

    2. 结果如下图

     

          主线程首先创建了一个 Counter的实例对象,这个类定义了一个可以增,可以 减的简单计数器。然后我们创建了三个线程,这三个线程共享一个Counter对象。由于没有对共享变量的锁定,所以在一个周期内,对共享变量的改变,在上个线程没结束之前,当前线程又对共享变量进行了操作,我们会得到不同的计数值,如上图所示。为了防止这种情况的发生,所以我们要对共享变量进行加锁。使用lock关键字锁定对象,这样在一个线程操作完成之前,其他线程都不能对共享变量进行操作。

     

    十一、Moniter对资源的锁定

     1.代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading; //引入线程
    using System.Diagnostics; 
    
    namespace ThreadConsoleApp
    {   
     class Program
        {
            static void Main(string[] args)
            {
    
                Console.WriteLine("开始,线程死锁");          
    
                var lock1 = new object();
                var lock2 = new object();
               
    
                Thread t = new Thread(()=> DeadLock(lock1,lock2));
                t.Name = "线程1";       
    
                //启动线程
    
                t.Start();
                lock (lock2)
                {
                    Thread.Sleep(2000); 
    
                    if (Monitor.TryEnter(lock1,TimeSpan.FromSeconds(5)))
    
                    {
                        Console.WriteLine("在规定时间内,请求资源");
    
                    }
                    else
    
                    {
                        Console.WriteLine("超时,无法获取资源");
    
                    }
                }
    
                new Thread(() => DeadLock(lock1, lock2)).Start();
                 Console.WriteLine("-----------------------------");
    
                lock (lock2)
                {
    
                    Thread.Sleep(1000);
                    Console.WriteLine(string.Format("死锁线程"));
    
                   lock(lock1)
                    {
                        Console.WriteLine("请求资源成功");
    
                    }          
               }
    
                Console.Read();
            }
          
    
            /// <summary>
            /// 死锁方法
            /// </summary>
            /// <param name="objLock1"></param>
            /// <param name="objLock2"></param>
            static void DeadLock(object objLock1,object objLock2)
            {
                lock (objLock1)
                {
                    Thread.Sleep(2000);
                    lock (objLock2)
                    {
                        Console.WriteLine("死锁");
                    }
                }
            }
        }
    }

    2.结果如下图

     

     先看deadlock方法,这个方法先锁定lock1对象,然后等待2秒之后,锁定了lock2对象。然后在子线程中启动了这个方法。

    主线程中先锁定了lock2对象,然后等待获取lock1对象。由于子线程锁定了lock1对象,等待lock2对象。所以造成了死锁。

     

    十二、多线程的异常处理

     1.代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading; //引入线程
    using System.Diagnostics;
     
    namespace ThreadConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                Console.WriteLine("开始,异常处理");          
                Thread t = new Thread(FaultyThread);
                t.Name = "线程1";        
    
                //启动线程
                t.Start();
                t.Join();
                try
                {
                    t = new Thread(ExpectThread);
                    t.Start();
                }
    
                catch (Exception ex)
                {
                    Console.WriteLine("异常信息:" + ex.Message);
                }
                Console.Read();
            }    
    
            static void ExpectThread()
            {
                Console.WriteLine(string.Format("异常处理"));
                Thread.Sleep(2000);
                throw new Exception("抛出异常");
            }
            static void FaultyThread()
            {
                try
                {
                    Console.WriteLine(string.Format("异常处理2"));
                    Thread.Sleep(1000);
                    throw new Exception("抛出异常2");
                }
    
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("异常处理2:{0}",ex.Message));
                }        
    
            }
        }
    }

     2.结果如下图。

     

     在程序中定义了两个处理异常的方法,一个对异常进行了处理,另一个没有对异常进行处理。最后如图。程序崩溃了。

  • 相关阅读:
    docker安装部署命令
    kubernetes原理
    kubernetes安装部署
    Ansible安装
    模拟红绿灯(递归与队列)
    数据结构——顺序表
    数据结构——基本概念
    C语言高级编程
    Shell编程
    Shell命令
  • 原文地址:https://www.cnblogs.com/chillsrc/p/7728578.html
Copyright © 2020-2023  润新知