C#多线程基础知识汇总
作者:萌萌丶小魔王 发布时间:2023-03-06 08:35:47
最近自己写了个小爬虫,里面用到了多线程技术,忽然发现对此技术竟然有些陌生了,于是乎开始疯狂的去问度娘,在此记录下来,以便自己和各位小伙伴们学习。
一、什么是线程
一个应用程序就相当于一个进程,进程拥有应用程序的所有资源进程包括线程,进程的资源被线程共享,但不拥有线程。我们可以打开电脑中的任务管理器,运行的.exe都是一个进程,里面的分支是线程。
二、多线程
多线程其实就是进程中一段并行运行的代码
1. 创建并启动线程
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
var thread = new Thread(Test1);
thread.Start();
Console.WriteLine(threadId + "_Main()");
Console.Read();
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test1()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine(threadId + "_Test()");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(threadId + "_" + i);
}
}
结果:
2、暂定线程诺干时间
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
var thread = new Thread(Test1);
thread.Start();
Console.WriteLine($"主线程Id{threadId}_Main()");
Console.Read();
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test1()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"辅线程Id{threadId}_Test()");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);//单位毫秒
Console.WriteLine($"辅线程Id{threadId}_{DateTime.Now}");
}
}
结果:
3、线程合并
Thread.Join操作会阻塞当前线程,等待子线程完成后再进行运行。
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
var thread = new Thread(Test1);
thread.Start();
Console.WriteLine($"主线程Id{threadId}_Main()1");
thread.Join();
Console.WriteLine($"主线程Id{threadId}_Main()2");
Console.Read();
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test1()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"辅线程Id{threadId}_Test()");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);//单位毫秒
Console.WriteLine($"辅线程Id{threadId}_{DateTime.Now}");
}
}
结果:
4、线程终止
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
var thread = new Thread(Test1);
thread.Start();
Console.WriteLine($"主线程Id{threadId}_Main()1");
Thread.Sleep(3000);
thread.Abort();
Console.WriteLine($"主线程Id{threadId}_Main()2");
Console.Read();
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test1()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"辅线程Id{threadId}_Test()");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);//单位毫秒
Console.WriteLine($"辅线程Id{threadId}_{DateTime.Now}");
}
}
结果:
5、线程中的参数传递
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"主线程Id{threadId}_Main()");
//第一种参数传递方式
var thread1 = new Thread(() => Test1("小魔王"));
thread1.Start();
//第二种参数传递方式(参数只能是一个,object类型)
var parameterizedThreadStart = new ParameterizedThreadStart(Test2);
var thread2 = new Thread(parameterizedThreadStart);
thread2.Start("大魔王");
Console.Read();
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test1(string name)
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"辅线程Id{threadId}_我的名字叫:{name}");
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test2(object name)
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"辅线程Id{threadId}_我的名字叫:{name}");
}
结果:
还有其他的传递方式,在此先不做说明了,这里只介绍Thread提供的这么几种。
6、线程安全和线程锁Lock
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。线程安全情况下,不会出现数据不一致或者数据污染的问题。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据! 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
lock 关键字通过获取指定对象的互斥锁,将语句块标记为临界区,执行语句然后释放该锁。
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。使用Lock,会导致整个应用程序串行化,降低程序的并发能力,影响性能。
到底什么场景下要使用lock保证线程安全:该串行就串行,该并行就并行。
加锁前:
public static int i = 1000000;
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
for (int j = 0; j < 2; j++)
{
var thread = new Thread(Test1);
thread.Start();
}
Console.Read();
}
/// <summary>
/// 测试方法
/// </summary>
private static void Test1()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"辅线程Id{threadId}_i初始值:{i}");
int count = 0;
for (int j = 0; j < 1000000; j++)
{
i--;
count++;
}
Console.WriteLine($"辅线程Id{threadId}_运行次数:{count}");
Console.WriteLine($"辅线程Id{threadId}_i结束值:{i}");
}
结果:
加锁后:
public static int i = 1000000;
private readonly static object objLock = new object();
static void Main()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
for (int j = 0; j < 2; j++)
{
var thread = new Thread(Test1);
thread.Start();
}
Console.Read();
}
private static void Test1()
{
//获取线程Id
var threadId = Thread.CurrentThread.ManagedThreadId;
int count = 0;
lock (objLock)
{
Console.WriteLine($"辅线程Id{threadId}_i初始值:{i}");
for (int j = 0; j < 1000000; j++)
{
i--;
count++;
}
}
Console.WriteLine($"辅线程Id{threadId}_运行次数:{count}");
Console.WriteLine($"辅线程Id{threadId}_i结束值:{i}");
}
结果:
好啦,今天关于线程的知识就分箱到这里啦。
来源:https://www.cnblogs.com/xiaomowang/p/11448414.html


猜你喜欢
- 本文实例讲述了C#获取每个年,月,周的起始日期和结束日期的方法。分享给大家供大家参考,具体如下:我们在写程序的时候往往要计算出年,月,周的开
- 在使用Java集合的时候,都需要使用Iterator。但是java集合中还有一个迭代器ListIterator,在使用List、ArrayL
- 现在我们的手机一般都内置有方向感应器,手机屏幕会根据所处位置自动进行横竖屏切换(前提是未锁定屏幕方向)。但有时我们的应用程序仅限在横屏或者竖
- 1、系统信息:Windows10 64位2、环境搭建参考:https://www.jb51.net/article/185086.htm3、
- 本文实例讲述了Java Arrays工具类用法。分享给大家供大家参考,具体如下:Arrays类功能描述Arrays类是一个工具类,其中包含了
- 可扩展标记语言(XML)文件是一种标准的文本文件,它使用特定的标记来描述文档的结构以及其他特性。通过将XML转换为PDF,能够便于文件传输及
- (1)自定义泛型链表类。public class GenericList<T> { 
- 一、简介Mutex的突出特点是可以跨应用程序域边界对资源进行独占访问,即可以用于同步不同进程中的线程,这种功能当然这是以牺牲更多的系统资源为
- @MapperScan包扫描的坑在使用通用mapper执行查询时,由于不太注意顺手就导了spring的包:import org.mybati
- ActivityThread功能它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IAppl
- 举例说明自定义C++异常处理的实例例1:自定义一个继承自excepton的异常类myExceptionC++标准中,定义在<stdex
- 目录前言一、小提二、将传感器改成事件分发机制三、使用四、源码总结前言在之前写了一篇关于3D效果的文章,借助传感器展示,有小伙伴问可不可以改成
- 其中包含两个jsp文件,分别为login.jsp和index.jsp代码如下:login.jsp<%@ page language=&
- 装箱(boxing)和拆箱(unboxing)是C#类型系统的核心概念.是不同于C与C++的新概念!,通过装箱和拆箱操作,能够在值类型和引用
- Q:使用过滤器、 * 与切片实现每个请求耗时的统计,并比较三者的区别与联系过滤器Filter 过滤器概念Filter是J2E中来的,可以看做
- 1、本篇内容本文让大家掌握 springmvc 中异步处理请求,特别牛逼的一个功能,大家一定要掌握。2、看段代码,分析问题@Response
- SpringBoot如何快速配置数据源;有如下两种方式:通过spring-boot-starter-jdbc快速配置数据源自定义数据源Dat
- 1. 日志框架的选择:(这两个框架,springBoot已经整合,无需引入jar包)2. 在resources目录下配置logback-sp
- 目录一、什么是vector数组二、vector的基本操作vector数组的初始化向vector中插入元素删除元素遍历数组利用vector创建
- 用来记录自己所用到的知识前两天在做项目的时候发现有时候在访问网络数据的时候由于后台要做的工作较多,给我们返回数据的时间较长,所以老大叫我加了