zoukankan      html  css  js  c++  java
  • C#多线程基础

    感谢大哥 https://www.cnblogs.com/xiaomowang/p/11448414.html

    一、什么是线程

    一个应用程序就相当于一个进程,进程拥有应用程序的所有资源进程包括线程,进程的资源被线程共享,但不拥有线程。我们可以打开电脑中的任务管理器,运行的.exe都是一个进程,里面的分支是线程。

    二、多线程

    多线程其实就是进程中一段并行运行的代码

    1. 创建并启动线程

    复制代码
     1         static void Main()
     2         {
     3             //获取线程Id
     4             var threadId = Thread.CurrentThread.ManagedThreadId;
     5             var thread = new Thread(Test1);
     6             thread.Start();
     7 
     8             Console.WriteLine(threadId + "_Main()");
     9             Console.Read();
    10         }
    11 
    12         /// <summary>
    13         /// 测试方法
    14         /// </summary>
    15         private static void Test1()
    16         {
    17             //获取线程Id
    18             var threadId = Thread.CurrentThread.ManagedThreadId;
    19             Console.WriteLine(threadId + "_Test()");
    20             for (int i = 0; i < 10; i++)
    21             {
    22                 Console.WriteLine(threadId + "_" + i);
    23             }
    24         }
    复制代码

    结果:

     2、暂定线程诺干时间

    复制代码
     1         static void Main()
     2         {
     3             //获取线程Id
     4             var threadId = Thread.CurrentThread.ManagedThreadId;
     5             var thread = new Thread(Test1);
     6             thread.Start();
     7             Console.WriteLine($"主线程Id{threadId}_Main()");
     8             Console.Read();
     9         }
    10 
    11         /// <summary>
    12         /// 测试方法
    13         /// </summary>
    14         private static void Test1()
    15         {
    16             //获取线程Id
    17             var threadId = Thread.CurrentThread.ManagedThreadId;
    18             Console.WriteLine($"辅线程Id{threadId}_Test()");
    19             for (int i = 0; i < 10; i++)
    20             {
    21                 Thread.Sleep(1000);//单位毫秒
    22                 Console.WriteLine($"辅线程Id{threadId}_{DateTime.Now}");
    23             }
    24         }
    复制代码

    结果:

     3、线程合并

    Thread.Join操作会阻塞当前线程,等待子线程完成后再进行运行。

    复制代码
     1         static void Main()
     2         {
     3             //获取线程Id
     4             var threadId = Thread.CurrentThread.ManagedThreadId;
     5             var thread = new Thread(Test1);
     6             thread.Start();
     7             Console.WriteLine($"主线程Id{threadId}_Main()1");
     8             thread.Join();
     9             Console.WriteLine($"主线程Id{threadId}_Main()2");
    10             Console.Read();
    11         }
    12 
    13         /// <summary>
    14         /// 测试方法
    15         /// </summary>
    16         private static void Test1()
    17         {
    18             //获取线程Id
    19             var threadId = Thread.CurrentThread.ManagedThreadId;
    20             Console.WriteLine($"辅线程Id{threadId}_Test()");
    21             for (int i = 0; i < 10; i++)
    22             {
    23                 Thread.Sleep(1000);//单位毫秒
    24                 Console.WriteLine($"辅线程Id{threadId}_{DateTime.Now}");
    25             }
    26         }
    复制代码

    结果:

     4、线程终止

    复制代码
     1         static void Main()
     2         {
     3             //获取线程Id
     4             var threadId = Thread.CurrentThread.ManagedThreadId;
     5             var thread = new Thread(Test1);
     6             thread.Start();
     7             Console.WriteLine($"主线程Id{threadId}_Main()1");
     8             Thread.Sleep(3000);
     9            thread.Abort();
    10             Console.WriteLine($"主线程Id{threadId}_Main()2");
    11             Console.Read();
    12         }
    13 
    14         /// <summary>
    15         /// 测试方法
    16         /// </summary>
    17         private static void Test1()
    18         {
    19             //获取线程Id
    20             var threadId = Thread.CurrentThread.ManagedThreadId;
    21             Console.WriteLine($"辅线程Id{threadId}_Test()");
    22             for (int i = 0; i < 10; i++)
    23             {
    24                 Thread.Sleep(1000);//单位毫秒
    25                 Console.WriteLine($"辅线程Id{threadId}_{DateTime.Now}");
    26             }
    27         }
    复制代码

    结果:

     5、线程中的参数传递

    复制代码
     1 static void Main()
     2         {
     3             //获取线程Id
     4             var threadId = Thread.CurrentThread.ManagedThreadId;
     5             Console.WriteLine($"主线程Id{threadId}_Main()");
     6             //第一种参数传递方式
     7             var thread1 = new Thread(() => Test1("小魔王"));
     8             thread1.Start();
     9 
    10             //第二种参数传递方式(参数只能是一个,object类型)
    11             var parameterizedThreadStart = new ParameterizedThreadStart(Test2);
    12             var thread2 = new Thread(parameterizedThreadStart);
    13             thread2.Start("大魔王");
    14             Console.Read();
    15         }
    16 
    17         /// <summary>
    18         /// 测试方法
    19         /// </summary>
    20         private static void Test1(string name)
    21         {
    22             //获取线程Id
    23             var threadId = Thread.CurrentThread.ManagedThreadId;
    24             Console.WriteLine($"辅线程Id{threadId}_我的名字叫:{name}");
    25         }
    26 
    27         /// <summary>
    28         /// 测试方法
    29         /// </summary>
    30         private static void Test2(object name)
    31         {
    32             //获取线程Id
    33             var threadId = Thread.CurrentThread.ManagedThreadId;
    34             Console.WriteLine($"辅线程Id{threadId}_我的名字叫:{name}");
    35         }
    复制代码

    结果:

     还有其他的传递方式,在此先不做说明了,这里只介绍Thread提供的这么几种。

    6、线程安全和线程锁Lock

    线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。线程安全情况下,不会出现数据不一致或者数据污染的问题。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据! 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

    lock 关键字通过获取指定对象的互斥锁,将语句块标记为临界区,执行语句然后释放该锁。

    lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。使用Lock,会导致整个应用程序串行化,降低程序的并发能力,影响性能。

    到底什么场景下要使用lock保证线程安全:该串行就串行,该并行就并行。

    加锁前:

    复制代码
     1  public static int i = 1000000;
     2         static void Main()
     3         {
     4             //获取线程Id
     5             var threadId = Thread.CurrentThread.ManagedThreadId;
     6             for (int j = 0; j < 2; j++)
     7             {
     8                 var thread = new Thread(Test1);
     9                 thread.Start();
    10             }
    11             Console.Read();
    12         }
    13 
    14         /// <summary>
    15         /// 测试方法
    16         /// </summary>
    17         private static void Test1()
    18         {
    19             //获取线程Id
    20             var threadId = Thread.CurrentThread.ManagedThreadId;
    21            
    22             Console.WriteLine($"辅线程Id{threadId}_i初始值:{i}");
    23             int count = 0;
    24             for (int j = 0; j < 1000000; j++)
    25             {
    26                 i--;
    27                 count++;
    28             }
    29             Console.WriteLine($"辅线程Id{threadId}_运行次数:{count}");
    30             Console.WriteLine($"辅线程Id{threadId}_i结束值:{i}");
    31         }
    复制代码

    结果:

    加锁后:

    复制代码
     1  public static int i = 1000000;
     2         private readonly static object objLock = new object();
     3         static void Main()
     4         {
     5             //获取线程Id
     6             var threadId = Thread.CurrentThread.ManagedThreadId;
     7             for (int j = 0; j < 2; j++)
     8             {
     9                 var thread = new Thread(Test1);
    10                 thread.Start();
    11             }
    12             Console.Read();
    13         }
    14 
    15         private static void Test1()
    16         {
    17             //获取线程Id
    18             var threadId = Thread.CurrentThread.ManagedThreadId;
    19            
    20             int count = 0;
    21             lock (objLock)
    22             {
    23                 Console.WriteLine($"辅线程Id{threadId}_i初始值:{i}");
    24                 for (int j = 0; j < 1000000; j++)
    25                 {
    26                     i--;
    27                     count++;
    28                 }
    29             }
    30             Console.WriteLine($"辅线程Id{threadId}_运行次数:{count}");
    31             Console.WriteLine($"辅线程Id{threadId}_i结束值:{i}");
    32         }
    复制代码

    结果:

    好啦,今天关于线程的知识就分箱到这里啦。

  • 相关阅读:
    MySQL架构优化:定时计划任务与表分区
    关于mysql 删除数据后物理空间未释放(转载)
    Mysql删除数据后磁盘空间未释放的解决办法【转】
    Mysql 自动备份脚本
    迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上)【转载】
    Redis学习笔记(二)-key相关命令【转载】
    干货分享:MySQL之化险为夷的【钻石】抢购风暴【转载】
    Apache 实现ProxyPass转发URL到Tomcat并实现http自动转https【转载】
    业务零影响!如何在Online环境中巧用MySQL传统复制技术【转】
    VNC轻松连接远程Linux桌面
  • 原文地址:https://www.cnblogs.com/ning-xiaowo/p/13161788.html
Copyright © 2011-2022 走看看