【一文了解】线程的使用

目录

线程的使用

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)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值