当前位置: 首页 > news >正文

【一文了解】线程的使用

目录

线程的使用

1.基础语法

1.1.引用命名空间

1.2.创建线程的3种方式

(1)无参数方法

(2)带参数方法(参数必须是object类型)

(3)使用匿名函数(Lambda表达式)

2.线程的核心操作

2.1.线程等待(主线程等待子线程完成)

2.2.线程休眠(暂停执行一段时间)

2.3.强制终止线程(不推荐)

2.4.安全终止线程(推荐)

3.Unity中使用线程的特殊注意事项

3.1.禁止子线程调用UnityAPI

3.2.子线程与主线程通信(安全更新UI)

4.总结


       本篇文章分享一下线程该怎么使用。

线程的使用

       线程是进程内的最小执行单元,一个进程可以包含多个线程,所有线程共享该进程的内存空间和资源(如变量、文件句柄)。线程是操作系统调度的基本单位(CPU直接执行线程)

1.基础语法

1.1.引用命名空间

       在C#中,线程(Thread)的使用主要依赖System.Threading命名空间下的Thread类。

using System.Threading;

1.2.创建线程的3种方式

       线程的核心是“要执行的方法”,可以通过以下方式创建并绑定方法:

(1)无参数方法
//定义线程要执行的方法(无参数)
private void ThreadTask()
{Debug.Log($"子线程执行,线程ID:{Thread.CurrentThread.ManagedThreadId}");
}//创建并启动线程
Thread thread = new Thread(ThreadTask);//创建线程并绑定方法
thread.Start();//启动线程(线程进入就绪状态,等待CPU调度)

(2)带参数方法(参数必须是object类型)
//定义带参数的方法(参数类型必须为 object)
private void ThreadTaskWithParam(object message)
{string msg = (string)message; // 强制类型转换Debug.Log($"子线程收到消息:{msg},线程ID:{Thread.CurrentThread.ManagedThreadId}");
}//创建并启动线程(传递参数)
Thread thread = new Thread(ThreadTaskWithParam);//创建线程并绑定方法
thread.Start("Hello from main thread");//启动时传入参数

(3)使用匿名函数(Lambda表达式)
//直接通过 Lambda 定义线程任务(适合简单逻辑)
Thread thread = new Thread(() => 
{Debug.Log($"匿名线程执行,线程ID:{Thread.CurrentThread.ManagedThreadId}");
});
thread.Start();

2.线程的核心操作

2.1.线程等待(主线程等待子线程完成)

       使用Join()方法让主线程阻塞,直到子线程执行完毕

Thread thread = new Thread(() => 
{Thread.Sleep(2000);//子线程休眠2秒(模拟耗时操作)Debug.Log("子线程完成");
});thread.Start();
Debug.Log("主线程等待子线程完成...");
thread.Join();//主线程阻塞,直到子线程执行完毕
Debug.Log("主线程继续执行");

2.2.线程休眠(暂停执行一段时间)

       使用Thread.Sleep(int milliseconds)让当前线程暂停指定毫秒数

Thread thread = new Thread(() => 
{Debug.Log("子线程开始");Thread.Sleep(1000);//暂停1秒Debug.Log("子线程1秒后继续");
});
thread.Start();

2.3.强制终止线程(不推荐)

       使用Abort()强制终止线程,可能导致资源未释放,建议通过标志位安全终止

Thread thread = new Thread(() => 
{try{while (true){Debug.Log("子线程运行中...");Thread.Sleep(500);}}catch (ThreadAbortException){Debug.Log("子线程被强制终止");}
});thread.Start();
Thread.Sleep(2000);//主线程等待2秒
thread.Abort();//强制终止子线程

2.4.安全终止线程(推荐)

       通过bool标志位控制线程退出,避免资源泄漏

private bool isThreadRunning = true;//线程运行标志位private void StartThread()
{Thread thread = new Thread(LoopTask);thread.Start();
}private void LoopTask()
{while (isThreadRunning)//通过标志位控制循环{Debug.Log("子线程运行中...");Thread.Sleep(500);}Debug.Log("子线程安全退出");
}//外部调用此方法终止线程
private void StopThread()
{isThreadRunning = false;
}

3.Unity中使用线程的特殊注意事项

3.1.禁止子线程调用UnityAPI

       Unity绝大多数API(如Transform、GameObject、Debug.Log等)只能在主线程调用,子线程调用会报错

//错误示例:子线程调用 Unity API
Thread thread = new Thread(() => 
{//以下代码会导致崩溃!GameObject obj = new GameObject("Test"); Debug.Log("子线程调用Unity API"); 
});
thread.Start();

3.2.子线程与主线程通信(安全更新UI)

       通过“主线程调度器”将UI操作委托给主线程执行,如下例:文件读取与展示

(1)实现主线程调度器

using UnityEngine;
using System.Collections.Generic;/// <summary>
/// 主线程调度器:用于子线程向主线程投递任务(如更新 UI)
/// </summary>
public class MainThreadDispatcher : MonoBehaviour
{//单例实例private static MainThreadDispatcher instance;//主线程任务队列private readonly Queue<System.Action> mainThreadTasks = new Queue<System.Action>();//确保场景中只有一个调度器private void Awake(){if (instance == null){instance = this;}else{Destroy(gameObject);}}//主线程每帧执行任务队列private void Update(){lock (mainThreadTasks)//线程安全地访问任务队列{while (mainThreadTasks.Count > 0){//执行主线程任务(如更新 UI)mainThreadTasks.Dequeue()?.Invoke();}}}/// <summary>/// 向主线程投递任务/// </summary>/// <param name="task">要在主线程执行的任务(如 UI 操作)</param>public static void EnqueueTask(System.Action task){if (instance == null){Debug.LogError("MainThreadDispatcher 未初始化!请在场景中添加该脚本");return;}lock (instance.mainThreadTasks){instance.mainThreadTasks.Enqueue(task);}}
}

(2)子线程通过调度器更新UI

using UnityEngine;
using System.IO;
using System.Threading;
using TMPro;/// <summary>
/// 文件读取子线程
/// </summary>
public class FileReaderThread:MonoBehaviour
{public TextMeshProUGUI statusText;public TextMeshProUGUI resultText;private void Start(){resultText.text = "准备读取文件...";Thread thread = new Thread(FileReadThreadTask);statusText.text = "开始读取文件";thread.Start();}private void FileReadThreadTask(){Thread.Sleep(2000);string filePath =Path.Combine(Application.streamingAssetsPath, "file.txt");string content = File.ReadAllText(filePath);MainThreadDispatcher.EnqueueTask(() =>{resultText.text = content;statusText.text = "文件读取完成!";});}
}

4.总结

       线程主要用于处理“不涉及UnityAPI的耗时任务”(CPU密集型任务,如数据计算;IO密集型任务,如文件读写),使用时需注意线程安全(共享数据加锁)和Unity API调用限制

想要进一步了解进程、线程和协程可以查看【一文了解】Unity的协程(Coroutine)与线程(Thread)和区分进程(Process)、线程(Thread)和协程(Coroutine)

       好了,本次的分享到这里就结束啦,希望对你有所帮助~

http://www.dtcms.com/a/391664.html

相关文章:

  • 电力系统暂态稳定计算与单机无穷大系统建模
  • OmniGen2 - 智源研究院推出的开源多模态生成模型
  • 【故障排查:JDK8中Files.lines方法错误使用导致的Linux服务器文件描述符泄漏问题】
  • 【multisim仿真电子秒表74LS90】2022-12-15
  • v-show 和 v-if 的区别及使用场景
  • 动态二维码杜绝代签,手机端配置同步,巡检数据更可靠
  • 数据库学习MySQL系列6、MySQL入门简单练习使用
  • 交互式生成对抗网络(iGAN)
  • RecSys: 推荐系统重排与多样性优化(MMR以及DPP算法)
  • 瑞芯微MPP音视频框架---mjpeg解码
  • 模型部署:(七)安卓端部署OCR文本识别项目全流程记录
  • 用html5写一个超级计算器
  • 手机实现真随机数生成器
  • 119.计数器产生中断(上升沿)计算方法,比如cnt[21:0],那么assign time = cnt[20]这样大致是多长时间产生一次中断
  • VSCode c/c++头文件函数点击无法跳转问题
  • `mysql_real_connect` 函数全面深度解析
  • 深入解析Yum元数据安全与Artifactory自动化原理
  • 第三章 强化学习助力优化
  • 使用角色和Ansible内容集合简化Playbook
  • 鸿蒙应用集成Push Kit 指南
  • 树莓派ubuntu20.04实现ROS noetic与Arduino通信
  • 【代码随想录算法训练营——Day17】二叉树——654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
  • 托福听力44
  • C++——STL
  • 「ECG信号处理——(25)基于ECG心率变异性(HRV)与EDA皮肤电活动的生理状态分析」2025年9月19日
  • 高通camx架构学习(四)——Camera Framework
  • 接口安全攻防战:从入门到精通的全方位防护指南
  • GEO(Generative Engine Optimization)技术详解与2025实践指南
  • Amazon SES 移出沙盒完整指南 高通过率模板
  • 从 IP over 鸽子到 TCP 的适应性