10-C#.Net-多线程-进阶篇-学习笔记

C# 学习笔记 C# 学习笔记 1 发展概况 1.1 C#版本历史 参考 Version .Net Visual Studio Important Features C# 1.0 .NET Framework 1.0 Visual Studio 2002 Basic features C# 2.0 .NET Framework 2.0 Visual Studio 2005 Generics C# 3.0 .NET Framework 3.0 Visual Studio 2008 Lambda exp 阅读详情

一、Parallel 并行编程

1.1 Parallel.Invoke

基本用法

// 一次执行多个委托
Parallel.Invoke(
    () => { DoWork1(); },
    () => { DoWork2(); },
    () => { DoWork3(); }
);

特点

  • 可以传入多个委托
  • 会开启线程执行(可能是新线程,也可能是主线程参与)
  • 会阻塞主线程,相当于主线程等待所有子线程执行结束

限制线程数量

ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3; // 最多开启3个线程

Parallel.Invoke(options,
    () => { DoWork1(); },
    () => { DoWork2(); },
    () => { DoWork3(); },
    () => { DoWork4(); },
    () => { DoWork5(); }
);

不阻塞界面的方式

Task.Run(() =>
{
    Parallel.Invoke(
        () => { DoWork1(); },
        () => { DoWork2(); },
        () => { DoWork3(); }
    );
});

1.2 Parallel.For

基本用法

// 100个任务,限制3个线程执行
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3;

Parallel.For(0, 100, options, index =>
{
    Console.WriteLine($"index: {index}, 线程ID: {Thread.CurrentThread.ManagedThreadId:00}");
    DoWork(index);
});

核心价值

  • 控制线程数量,避免线程泛滥
  • 100个任务不会开启100个线程
  • 3个线程平摊100个任务
  • 既提高性能,又不过度消耗资源

1.3 Parallel.ForEach

基本用法

List<int> dataList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3; // 3个线程处理10个任务

Parallel.ForEach(dataList, options, item =>
{
    Console.WriteLine($"处理: {item}, 线程ID: {Thread.CurrentThread.ManagedThreadId:00}");
    ProcessData(item);
});

应用场景

  • 批量数据处理
  • 文件批量操作
  • 大量计算任务

1.4 Parallel总结

优点

  • 基于Task的封装,使用简单
  • 自动控制线程数量
  • 避免线程过多导致资源浪费

使用建议

  • 有大量独立任务时使用
  • 需要控制并发数量时使用
  • 任务之间无依赖关系时使用

二、多线程异常处理

2.1 异常捕获问题

普通try-catch无法捕获多线程异常

try
{
    Task task = Task.Run(() =>
    {
        int i = 0;
        int j = 10;
        int k = j / i; // 除以0异常
    });
    // 异常被吞掉,捕获不到
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message); // 不会执行
}

2.2 正确的异常捕获

方法1:使用Wait等待

try
{
    Task task = Task.Run(() =>
    {
        int i = 0;
        int j = 10;
        int k = j / i;
    });
    
    task.Wait(); // 必须等待,才能捕获异常
}
catch (AggregateException aex) // 多线程异常类型
{
    Console.WriteLine(aex.Message);
    foreach (var innerEx in aex.InnerExceptions)
    {
        Console.WriteLine(innerEx.Message);
    }
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

方法2:多个任务的异常处理

try
{
    List<Task> tasks = new List<Task>();
    
    for (int i = 0; i < 20; i++)
    {
        string keyword = $"Task_{i}";
        tasks.Add(Task.Run(() =>
        {
            Thread.Sleep(new Random().Next(50, 100));
            
            if (keyword == "Task_6")
                throw new Exception("Task_6异常");
            if (keyword == "Task_9")
                throw new Exception("Task_9异常");
            if (keyword == "Task_12")
                throw new Exception("Task_12异常");
        }));
    }
    
    Task.WaitAll(tasks.ToArray());
}
catch (AggregateException aex)
{
    // 遍历所有内部异常
    foreach (var exception in aex.InnerExceptions)
    {
        Console.WriteLine(exception.Message);
    }
}

2.3 异常类型优先级

catch (AggregateException aex) // 具体异常类型,优先匹配
{
    // 处理多线程异常
}
catch (Exception ex) // 抽象异常类型,其次匹配
{
    // 处理其他异常
}

三、线程取消(CancellationToken)

3.1 线程取消原理

核心概念

  • 线程无法从外部取消,只能自己取消自己
  • 线程取消本质是向外抛出异常
  • 使用CancellationTokenSource统一管理

3.2 标准的线程取消

基本用法

CancellationTokenSource cts = new CancellationTokenSource();

// cts.IsCancellationRequested 默认为 false
// cts.Cancel() 执行后,变为 true(只能从false变true,不可逆)

Task task = Task.Run(() =>
{
    // 检查是否取消
    if (cts.IsCancellationRequested)
    {
        Console.WriteLine("任务被取消");
        return;
    }
    
    // 或者直接抛出异常
    cts.Token.ThrowIfCancellationRequested();
    
    // 执行任务
    DoWork();
    
}, cts.Token);

// 取消任务
cts.Cancel();

3.3 实际应用场景

场景:多个任务,一个失败全部取消

try
{
    List<Task> tasks = new List<Task>();
    CancellationTokenSource cts = new CancellationTokenSource();
    
    for (int i = 0; i < 100; i++)
    {
        string keyword = $"Task_{i}";
        tasks.Add(Task.Run(() =>
        {
            Thread.Sleep(new Random().Next(10, 300));
            
            // 任务开始前检查
            cts.Token.ThrowIfCancellationRequested();
            
            try
            {
                if (keyword == "Task_6")
                {
                    throw new Exception("Task_6异常");
                }
                
                // 执行任务
                DoWork();
            }
            catch (Exception)
            {
                cts.Cancel(); // 发生异常,取消所有任务
                throw;
            }
            
            // 任务结束前检查
            cts.Token.ThrowIfCancellationRequested();
            
        }, cts.Token)); // 传入Token,未开始的任务不再开启
    }
    
    Task.WaitAll(tasks.ToArray());
}
catch (AggregateException aex)
{
    foreach (var exception in aex.InnerExceptions)
    {
        Console.WriteLine(exception.Message);
    }
}

3.4 线程取消的三种情况

  • 已经结束的线程:无法取消(管不住)
  • 正在执行的线程:可以取消,抛出异常结束
  • 还未开始的线程:不再开启,直接跳过

四、线程安全

4.1 什么是线程安全

定义

  • 一段业务逻辑,单线程执行和多线程执行的结果完全一致,就是线程安全
  • 否则就是线程不安全

线程不安全示例

List<int> list = new List<int>();

// 单线程:结果是10000
for (int i = 0; i < 10000; i++)
{
    list.Add(i);
}
Console.WriteLine(list.Count); // 10000

// 多线程:结果不确定
List<int> list2 = new List<int>();
for (int i = 0; i < 10000; i++)
{
    Task.Run(() =>
    {
        list2.Add(i);
    });
}
Thread.Sleep(5000);
Console.WriteLine(list2.Count); // 可能是9937、9976、9982等

4.2 解决线程安全的方法

方法1:加锁(不推荐)

private readonly static object lockObj = new object();

List<int> list = new List<int>();
for (int i = 0; i < 10000; i++)
{
    Task.Run(() =>
    {
        lock (lockObj) // 加锁,独占资源
        {
            list.Add(i);
        }
    });
}

注意事项

  • 锁对象定义:private readonly static object lockObj = new object();
  • 不要锁String类型
  • 不要锁this
  • 加锁会影响性能,相当于反多线程

方法2:分块/分区执行(推荐)

List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
List<int> list3 = new List<int>();

int total = 10000;
int part1 = 3000;
int part2 = 6000;
int part3 = 10000;

List<Task> tasks = new List<Task>();

// 分三块,每块单线程执行(线程安全)
tasks.Add(Task.Run(() =>
{
    for (int i = 0; i < part1; i++)
    {
        list1.Add(i);
    }
}));

tasks.Add(Task.Run(() =>
{
    for (int i = part1; i < part2; i++)
    {
        list2.Add(i);
    }
}));

tasks.Add(Task.Run(() =>
{
    for (int i = part2; i < part3; i++)
    {
        list3.Add(i);
    }
}));

Task.WaitAll(tasks.ToArray());

// 单线程汇总
list1.AddRange(list2);
list1.AddRange(list3);
Console.WriteLine(list1.Count); // 10000

方法3:使用线程安全集合(推荐)

// 线程安全的集合类型
BlockingCollection<int> blockingList = new BlockingCollection<int>();
ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
ConcurrentDictionary<string, int> concurrentDict = new ConcurrentDictionary<string, int>();
ConcurrentQueue<int> concurrentQueue = new ConcurrentQueue<int>();
ConcurrentStack<int> concurrentStack = new ConcurrentStack<int>();

// 使用示例
ConcurrentBag<int> bag = new ConcurrentBag<int>();
for (int i = 0; i < 10000; i++)
{
    Task.Run(() =>
    {
        bag.Add(i); // 线程安全,无需加锁
    });
}
Thread.Sleep(5000);
Console.WriteLine(bag.Count); // 10000

4.3 线程安全总结

方法优点缺点推荐度
加锁简单直接性能差,本质上是把多线程退化成串行⭐
分块执行性能好,设计优雅需要设计分区逻辑⭐⭐⭐⭐⭐
线程安全集合简单,性能好需要替换数据结构⭐⭐⭐⭐⭐

⚠️ 加锁虽然能解决问题,但锁的范围内代码实际上是串行执行的,等于抵消了多线程的并发优势,只在没有更好方案时才考虑。

五、中间变量问题

5.1 问题现象

// 错误示例:所有线程输出的i都是5
for (int i = 0; i < 5; i++)
{
    Task.Run(() =>
    {
        Console.WriteLine($"i = {i}"); // 输出:5, 5, 5, 5, 5
    });
}

5.2 问题原因

  1. Task开启线程有延迟(虽然很短)
  2. 开启多线程不会阻塞主线程
  3. 循环很快,当线程真正执行时,循环已结束
  4. 此时i已经变成5

5.3 解决方案

// 正确示例:使用中间变量
for (int i = 0; i < 5; i++)
{
    int k = i; // 每次循环创建新的变量
    Task.Run(() =>
    {
        Console.WriteLine($"i = {i}, k = {k}"); 
        // i输出5,k输出0,1,2,3,4
    });
}

原理

  • 每次循环创建新的变量k
  • 每个线程使用的是各自循环内的k
  • k的值在创建时就已确定

六、实战案例:双色球开奖系统

6.1 需求分析

规则

  • 6个红球(01-33,不重复)
  • 1个蓝球(01-16)
  • 点击开始,所有球同时跳动变化
  • 点击停止,显示最终结果

技术要点

  • 7个球 = 7个线程
  • 每个线程独立运行,相互不影响
  • 红球需要去重
  • 避免死锁

6.2 核心代码

private bool isRunning = true;
private List<Task> taskList = new List<Task>();
private static object lockObj = new object();

private void btnStart_Click(object sender, EventArgs e)
{
    isRunning = true;
    taskList.Clear();
    
    // 遍历所有Label控件
    foreach (var control in gboSSQ.Controls)
    {
        if (control is Label label)
        {
            taskList.Add(Task.Run(() =>
            {
                if (label.Name.Contains("Blue")) // 蓝球
                {
                    while (isRunning)
                    {
                        int index = new RandomHelper().GetRandomNumberDelay(0, 16);
                        string num = blueNums[index];
                        
                        this.Invoke(new Action(() =>
                        {
                            label.Text = num;
                        }));
                    }
                }
                else // 红球
                {
                    while (isRunning)
                    {
                        int index = new RandomHelper().GetRandomNumberDelay(0, 33);
                        string num = redNums[index];
                        
                        lock (lockObj)
                        {
                            var currentNums = GetCurrentRedNumbers();
                            if (!currentNums.Contains(num))
                            {
                                this.Invoke(new Action(() =>
                                {
                                    label.Text = num;
                                }));
                            }
                        }
                    }
                }
            }));
        }
    }
    
    // 所有任务完成后的回调
    Task.Factory.ContinueWhenAll(taskList.ToArray(), tasks =>
    {
        this.Invoke(new Action(() =>
        {
            ShowResult();
            isRunning = true;
        }));
    });
}

private void btnStop_Click(object sender, EventArgs e)
{
    isRunning = false;
    // 不能在这里Wait,会死锁
    // Task.WaitAll(taskList.ToArray()); // 死锁!
}

6.3 关键技术点

1. 随机数去重

public class RandomHelper
{
    public int GetRandomNumber(int min, int max)
    {
        Guid guid = Guid.NewGuid();
        int seed = DateTime.Now.Millisecond;
        
        // 使用GUID增加随机性
        foreach (char c in guid.ToString())
        {
            seed += GetSeedIncrement(c);
        }
        
        Random random = new Random(seed);
        return random.Next(min, max);
    }
}

2. 跨线程更新UI

// 子线程不能直接操作UI,需要委托给主线程
this.Invoke(new Action(() =>
{
    label.Text = num;
}));

3. 避免死锁

// 错误:主线程等待子线程,子线程需要主线程更新UI
Task.WaitAll(taskList.ToArray()); // 死锁!

// 正确:使用回调
Task.Factory.ContinueWhenAll(taskList.ToArray(), tasks =>
{
    // 不阻塞主线程
});

七、小结

  • Parallel:控制线程数量,避免泛滥
  • 异常处理:使用 AggregateException,必须 Wait 才能捕获
  • 线程取消:CancellationTokenSource 统一管理
  • 线程安全:优先使用分块或线程安全集合,加锁是最后手段
  • 中间变量:循环中开启线程时,必须用临时变量捕获循环值
  • 死锁:避免主线程和子线程相互等待
C# 实现多线程启动停止暂停继续 多线程编程是提升应用程序性能和响应能力的关键技术之一。C# 提供了强大的多线程支持,能够轻松创建并发任务,优化资源利用,并改善用户体验。然而,实现多线程的同时,如何安全有效地管理这些线程(如启动、停止、暂停和继续)是一个重要的问题。大部分初学者在学习C#上位机编程时,多线程是一个很难逾越的鸿沟,不合理地使用多线程,会导致经常出现各种奇怪的问题,这也是很多初学者不敢使用多线程的原因。但是在实际开发中,多线程是一个不可避免的技术栈,基本上每个项目都会使用到,因此学好多线程技术,很重要。 阅读详情

相关推荐

.NET 6与C# 10性能改进及MAUI前景分析

本文介绍了.NET 6在垃圾回收、JIT编译、文本处理、正则表达式等方面的性能提升,以及C# 10的新特性如顶级语句和仅初始化属性。同时探讨了提高Windows应用商店应用性能的方法,并分析了.NET MAUI作为跨平台开发框架的发展趋势。最后建议使用Benchmark.NET对应用进行性能测试,评估升级至.NET 6和C# 10后的性能变化。

terraform7cloud的博客 881

C#学习笔记(上)

经本人搜集网上资料后整合而成的C#学习笔记,知识点很全面,前面某些很基础的内容绝大部分人都已经在学C/C++的时候学过了,所以基本一笔带过,其它地方都尽量写的很详细。

m0_75104457的博客 2315

C#.NET多线程编程全方位实例教程201902

htmltable {th, td {th {pre {简介:本教程旨在通过实例深入解析.NET框架下C#语言的多线程编程,涵盖了从基础使用到互斥的高级概念。介绍了线程创建、同步机制、线程优先级、生命周期,以及线程互斥的策略,包括Monitor和Mutex的使用。此外,还包括了ThreadPool、Task并行库TPL和async/await的高级技术。六个实例演示了如何在实际场景中应用这些技术,帮助开发者理解并掌握多线程编程,提高程序性能。

weixin_28713083的博客 1048

C# .NET多线程之Task的使用

C# .NET多线程之Task的使用C# .NET多线程之Task的使用背景需求Demo展示测试结果 C# .NET多线程之Task的使用 此文简单介绍下笔者的一点学习心得,希望对有需要的网友一些启发,不喜勿喷。 背景 公司最近公众号推送模板消息的需求频发,此公众号有60万以上用户,每次推送的人群由几千至十万以上不等,主要看目标用户群体划分,本来之前公众号很少量用户时,用for循环发送可以满足,但...

醉酒的李白、的博客 3890

C#.NET多线程编程与实例教程

本文还有配套的精品资源,点击获取 简介:C#在.NET框架中提供了丰富的多线程支持,本教程将详细介绍如何创建和管理线程,包括线程的基本使用、线程同步与互斥,以及线程安全的数据访问和异步编程模式。具体实现方法包括使用 Thread 类、 Monitor 、 Mutex 、 Semaphore 等关键字和类,以及 ...

weixin_35706067的博客 1357

C#.NET多线程批量下载项目实战源码

C#.NET,作为Microsoft开发的.NET框架的主流编程语言,拥有丰富的面向对象编程特性、类型安全和垃圾回收机制,这些都是为了简化程序开发并提高程序的稳定性和安全性。C#语言通过其简洁的语法、强大的语言特性和强大的开发库,使得开发者能够高效地构建各种企业级应用程序。C#语言的核心优势包括但不限于以下几个方面:面向对象的特性:支持封装、继承和多态,使得代码复用和模块化开发成为可能。类型安全:通过编译时类型检查确保类型转换的正确性,减少运行时错误。垃圾回收。

weixin_31597759的博客 848

C#与.NET多线程:优化、挑战与最新技术趋势

尤其是对于.NET平台而言,通过其多线程能力,可以充分利用多核处理器的优势,提升程序的并发处理能力。在本文中,我们将深入探讨.NET与C#多线程编程的发展历程,关注最新的特性与技术,并提供实际示例,帮助开发者更好地利用这些强大的工具。传统的多线程编程需要显式地创建和管理线程,而async/await则利用异步I/O操作,让开发者可以在不阻塞线程的情况下执行长时间运行的任务。随着.NET生态系统的不断更新,多线程编程的工具和框架也会继续发展,帮助开发者更好地应对多线程带来的挑战。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 973

C#.NET多线程编程实战:6个实例深入理解

简介:C#在.NET框架中提供了强大的多线程编程能力,使得开发者能够利用多核处理器进行并行处理。本资源包含了六个涵盖多线程基础和高级特性的C#.NET实例,如线程创建、线程同步与互斥、线程池使用、线程同步原语、异步编程模型、线程通信、线程状态管理、异常处理、线程局部存储和线程优先级等。开发者通过运行和分析这些实例,可以深入学习和掌握C#.NET多线程编程的实战应用。

weixin_31776191的博客 1368

VS2022+.NET6+C#10,.NET开发起飞

VS2022+.NET6+C#10一起体验是啥感觉?爽!令人印象深刻的是VS2022打开超大项目的流畅,.NET6极致简化的MiniAPI框架,C#10各种炫酷新语法。看看下图的代码你能认...

dotNET跨平台 5275

【Ultrascale+ MPSOC学习记录】6、从eMMC启动翻车

因为MPSOC还有一种启动模式是eMMC,接下来咱就实现从eMMC启动。

ryo891012的博客 474

群晖NAS实战:从零部署Container Manager与Docker代理配置全攻略

本文详细介绍了在群晖NAS上从零部署Container Manager与配置Docker代理的完整流程。针对国内用户常见的镜像拉取问题,提供了图形化界面与SSH命令行两种解决方案,并分享了MySQL容器部署的实战案例。文章特别强调了网络配置技巧和日常维护方法,帮助用户高效管理NAS上的容器应用。

weixin_29254673的博客 1300

.NET/C#⾯试题汇总系列:多线程

有⽤实现了IDisposiable的类在using中创建,using结束后会⾃定调⽤该对象的Dispose⽅法,释放资 源。using()语法的用途using语句在C#中非常有用,特别是在处理实现了接口的对象时。它确保了在代码块执行完毕后,会自动调用对象的Dispose方法,以释放非托管资源(如文件句柄、数据库连接等)。这不仅简化了资源管理,还避免了资源泄露的风险。什么是?是.NET中定义的一个接口,它包含一个Dispose方法。当一个类实现了。

微微的猪食小窝 1095

SigmaStudio进阶技巧:如何用ADAU1701实现60段EQ与防啸叫算法

本文深入探讨了如何在ADAU1701 DSP芯片上实现专业级音频处理系统。通过精密的资源规划与架构设计,详细讲解了构建高达60段参数均衡器(EQ)的有效方法,并集成了移频与自适应陷波双策略的智能防啸叫算法。内容涵盖从SigmaStudio工程优化、算法模块组合到系统联调实战的全流程,旨在帮助中高级开发者充分利用ADAU1701性能,打造稳定、高效的音频处理解决方案。

weixin_28256233的博客 384

【C#探索】.NET10 C#14前瞻

【C#14新特性前瞻】文章摘要:.NETConf2025将发布.NET10正式版,C#14带来多项重要更新:1.全新扩展方法语法,支持方法、属性及运算符扩展,提升函数式编程体验;2.幕后变量(field)自动生成简化属性定义;3.Null条件分配支持安全赋值;4.改进的JSON序列化支持PipeReader;5.简单lambda参数支持out修饰符;6.用户自定义复合运算符和分部构造函数;7.字符串数字排序优化。这些改进使C#更简洁高效,同时增强函数式编程能力。

scixing的博客 679

Win10环境借助DockerDesktop部署Open web UI集成DeepSeek

Win10环境借助DockerDesktop部署Open web UI集成DeepSeek,并借助DuckDuckGo实现联网查询

虎鲸不是鱼 1698

Open Dynamics Engine(ODE)物理引擎教程(1)--下载与安装准备

引言 ODE是一个免费的工业级库,用于模拟关节式刚体动力学,例如地面车辆、腿部生物和虚拟现实环境中的移动对象。它具有快速、灵活、健壮和独立于平台的特点,具有先进的关节、摩擦接触和内置的碰撞检测功能。 项目主页:http://www.ode.org/ 线上手册:http://ode.org/wiki/index.php?title=Manual 本教程为博主亲自亲测过程的总结,转载请注明出处! ...

腿足机器人领域 2216

.NET 10 的新特性_探索 C# 14、ASP.NET Core 和 .NET 10 中最有趣的新特性

本文介绍了C#和.NET生态中的多项新特性:1. C#14新增扩展成员功能,支持为类型添加属性、方法和事件;2. 空条件赋值简化空引用处理;3. 表达式树支持命名参数和可选参数;4. 复合赋值运算符允许自定义操作符。ASP.NET Core方面:1. 最小API支持数据注解验证;2. 新增服务器发送事件(SSE)支持。Blazor改进了路由配置,EF Core新增LeftJoin/RightJoin运算符和JSON类型支持。最后,.NET允许将应用程序存储在单个.cs文件中运行,无需项目文件。这些更新提升了

csdn_aspnet的专栏,请点击博客主页右上角三个点中的私信联系 5966

黑猫带你学eMMC协议第11篇:eMMC擦除详解(erase/trim/discard/sanitize/secure erase/secure trim...)

erase命令单位是擦除组,那么一个擦出组包含多个写块,不同写块有不同信息,主机擦除之前,必须进行确定好这些写块中的信息没有用了。所以通常erase用来擦除整个设备或分区。erase完成后,将erase的区域都要么是全0,要么是全1。那么到底是0还是1呢,根据不同的工艺有所不同,但是别担心,在ecsd[181]中会有说明到底是1还是0。erase命令的作用就是简单的将映射地址范围移动到未映射的地址范围。

黑猫奥利奥的博客 7794

.NET 10 重磅特性:无需项目的C#脚本执行方案

.NET 10新特性:dotnetrunapp.cs简化C#开发 .NET 10 Preview 4推出dotnetrunapp.cs功能,允许开发者直接运行单个C#文件,无需创建项目文件或复杂目录结构。通过文件级指令(如#:package引用NuGet包、#:sdk指定SDK),可快速构建脚本或小型应用,并支持shebang行跨平台执行。当代码复杂度增加时,使用dotnetprojectconvert无缝转换为完整项目。此功能降低C#入门门槛,保留与标准项目的一致性,为学习、实验和脚本开发提供高效方案。安

weixin_41541184的博客 2189

Centos 7 Linux 安装 JDK 8:下载、安装、配置环境变量、验证

本文详细介绍了在 CentOS 7 系统上手动安装 JDK 8 的完整流程,包括环境准备、JDK 安装包下载与上传、解压安装、配置全局环境变量,以及最终的验证步骤。适用于使用 VMware 虚拟机、云服务器或物理机的 CentOS 7 用户,操作清晰、步骤完整,帮助开发者快速搭建 Java 开发环境。

寒水馨 · 轻量级技术文档 · hanshuixin.org 2577

YOLO26优化:FPN涨点&轻量化篇 |多级特征融合金字塔(HS-FPN),助力小目标检测

高层筛选特征金字塔网络(HS-FPN),能够刷选出大小目标,增强模型表达不同尺度特征的能力,助力小目标检测

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 328

paip.C#.NET多线程访问 toolStripStatusLabel

paip.C#.NET多线程访问 toolStripStatusLabel 作者Attilax ,  EMAIL:1466519819@qq.com toolStripStatusLabel控件比较特殊,无法定义invoke来线程调用。。只好使用原生委托..代码稍微多一些..     delegate void clsC417(

attilax的专栏 4774

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C#/.NET 线程池ThreadPool多线程实现

线程池简介: 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程...

老陈聊架构 7239

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C#_.NET10_C#14_新特性详解

维度亮点性能JIT 编译提升 37.5%,GC 暂停减少 52%语言字段支持的属性、扩展属性让代码更简洁AI完整的 Agent 开发框架,MCP 协议支持生态三年 LTS 支持,企业级应用的可靠选择对于 C# 开发者来说,现在正是升级到 .NET 10 的最佳时机。无论是追求极致性能,还是探索 AI 应用开发,.NET 10 都提供了强大的工具和平台支持。

qq_16416731的博客 581

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

VS2022+.NET6 RC1+C#10,.NET开发起飞

9月14号发布了.NET6 RC1版本,代表着.NET6已基本定型了。小长假在家升级环境实操一番,VS2022+.NET6+C#10,那感觉简直了!VS2022超强智能提示,极致简化的AS...

dotNET跨平台 1457

C#学习笔记01之.NET与C#

.NET是Microsoft推出的用于软件开发、运行的平台,可以跨平台、跨语言开发,支持C#、F#、Visual Basic等语言。C#(读作“C Sharp”)是Microsoft推出的,由C和C++衍生出的,安全、稳定、简单、优雅的面向对象且运行于.NET Framework和.NET Core之上的高级程序编程语言,于2000年6月发布。它在继承C和C++强大功能的同时去掉了一些复杂特性如多重继承、内存管理,并提供了大量API以显著提高开发效率。

weixin_42449022的博客 1572
上一篇: 09-C#.Net-多线程-基础篇-学习笔记
下一篇: 11-C#.Net-多线程-Async-Await篇-学习笔记
似水明俊德
博客等级 码龄8年 247粉丝 276原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值