多线程编程学习笔记-基础

DotNet菜园 DotNet菜园     2022-09-24     533

关键词:

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

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

九、向线程传递参数

 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.结果如下图。

 

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

多线程编程学习笔记——线程池

 接上文 多线程编程学习笔记——线程同步(一) 接上文多线程编程学习笔记——线程同步(二) 接上文多线程编程学习笔记——线程同步(三)       创建多线程操作... 查看详情

多线程编程学习笔记——线程同步

接上文 多线程编程学习笔记——线程同步(一)接上文多线程编程学习笔记——线程同步(二)  七、使用Barrier类Barrier类用于组织多个线程及时在某个时刻会面,其提供一个回调函数,每次线程调用了Sig... 查看详情

多线程编程学习笔记——线程池

接上文多线程编程学习笔记——线程池(一) 三、线程池与并行度此示例是学习如何应用线程池实现大量的操作,及与创建大量线程进行工作的区别。1.代码如下usingSystem;usingSystem.Collections.Generic;usingSystem.Diagnostics;usingS... 查看详情

多线程编程学习笔记——任务并行库

接上文多线程编程学习笔记——任务并行库(一)接上文 多线程编程学习笔记——任务并行库(二) 六、  实现取消选项         本示例学习如何实现基于Task的异步操... 查看详情

多线程编程学习笔记——使用并发集合

接上文多线程编程学习笔记——使用并发集合(一)接上文多线程编程学习笔记——使用并发集合(二)  四、  使用ConcurrentBag创建一个可扩展的爬虫 本示例在多个独立的即可生产任务又可消费任... 查看详情

多线程编程学习笔记

多线程编程目录线程概述线程的创建创建线程程序线程同步守护线程线程之间的相互通讯线程池和java.util.concurrent包一、概述1.相关概念进程(Process):程序(任务)执行的过程,每个进程都有自己独立的一块内存空间,一个进程中可... 查看详情

多线程编程学习笔记——async和await

接上文多线程编程学习笔记——async和await(一)接上文多线程编程学习笔记——async和await(二)五、  处理异步操作中的异常     本示例学习如何在异步函数中处理异常,学习如何对多个并... 查看详情

多线程java多线程学习笔记|多线程基础知识(代码片段)

Java多线程学习笔记|多线程基础知识文章目录Java多线程学习笔记|多线程基础知识一.线程与进程二.Java中创建线程1.编写继承Thread的类,重写run方法2.编写实现Runnable的类,重写run方法3.其他方式的创建三.线程的生命周期四.... 查看详情

《c++多线程编程》学习笔记(代码片段)

文章目录线程安全的对象生命期管理当析构函数遇上多线程对象的创建对象池线程同步精要互斥器(mutex)条件变量(conditionvariable)慎用读写锁多线程服务器的适合模型与常用编程模型oneloopperthread+threadpool进... 查看详情

多线程编程学习笔记——async和await

接上文多线程编程学习笔记——async和await(一)三、  对连续的异步任务使用await操作符      本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步调用。1... 查看详情

c++学习笔记:高级编程:模板,预处理器,信号处理,多线程,web编程

模板模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单... 查看详情

学习笔记导航

...解第12章异常第13章常用类第14章集合第15章泛型第17章多线程编程第19章IO流第21章网络编程第23章反射第24章零基础学MySQL第25章JDBC和数据库连接池第27章正则表达式项目篇(09、16、18、20、22、26、28)廖雪峰教程Git教程SQL教... 查看详情

学习笔记导航

...解第12章异常第13章常用类第14章集合第15章泛型第17章多线程编程第19章IO流第21章网络编程第23章反射第24章零基础学MySQL第25章JDBC和数据库连接池第27章正则表达式项目篇(09、16、18、20、22、26、28)廖雪峰教程Git教程SQL教... 查看详情

scala学习笔记-actor(19)

Scala的Actor类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。此外,ScalaActor的... 查看详情

多线程编程学习笔记——编写一个异步的http服务器和客户端

接上文多线程编程学习笔记——使用异步IO 二、  编写一个异步的HTTP服务器和客户端本节展示了如何编写一个简单的异步HTTP服务器。 1.程序代码如下。usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Li... 查看详情

并发编程系列之线程基础知识回顾(代码片段)

并发线程的知识是很重要而且比较杂的知识点,所以需要花不少时间用于整理。本博客整理线程的一些比较重要而且比较基础的知识点,帮忙读者入门,注意只是学习并发编程的一些基础点,要系统学习的是需要... 查看详情

尚硅谷_java零基础教程(多线程)--学习笔记(代码片段)

Java多线程一、基本概念1、程序、进程、线程2、单核CPU和多核CPU、并行与并发3、使用多线程的优点二、线程的创建和使用1、API中创建线程的两种方式1.1、方式一:继承Thread类1.2、方式二:实现Runnable接口1.3、Thread类的调... 查看详情

转:学习笔记:delphi多线程学识

学习笔记:delphi多线程知识最近一直在温习旧的知识,刚好学习了一下Java的线程安全方面的知识,今天想起之前一直做的Delphi开发,所以还是有必要温习一下,看看这些不同的编程语言有什么不同之处。Delphi的线程同步方法:1... 查看详情