14、让线程等待一段时间

让线程等待一段时间

知识点概述

在多线程编程中,经常需要让线程暂停执行一段时间。.NET提供了多种方式来实现线程等待:

  • Thread.Sleep(): 使当前线程暂停指定的时间
  • Task.Delay(): 异步等待指定时间(推荐用于异步方法)
  • Thread.Yield(): 让出CPU时间片给其他线程
  • SpinWait: 忙等待,适用于短时间等待
  • ManualResetEvent/AutoResetEvent: 基于事件的等待机制

代码案例

案例1:Thread.Sleep基本用法

using System;
using System.Threading;
using System.Diagnostics;

class ThreadSleepDemo
{
    static void Main()
    {
        Stopwatch sw = Stopwatch.StartNew();
        
        Console.WriteLine($"开始时间: {DateTime.Now:HH:mm:ss.fff}");
        
        // 让主线程休眠2秒
        Thread.Sleep(2000);
        
        Console.WriteLine($"结束时间: {DateTime.Now:HH:mm:ss.fff}");
        Console.WriteLine($"实际耗时: {sw.ElapsedMilliseconds}ms");
    }
}

案例2:多线程中的Sleep应用

using System;
using System.Threading;

class MultiThreadSleepDemo
{
    static void Main()
    {
        // 创建多个线程,每个线程有不同的休眠时间
        for (int i = 1; i <= 3; i++)
        {
            int threadNum = i;
            Thread thread = new Thread(() => WorkWithSleep(threadNum));
            thread.Name = $"Thread-{threadNum}";
            thread.Start();
        }
        
        Console.WriteLine("主线程继续执行其他任务...");
        Thread.Sleep(5000); // 主线程等待5秒观察其他线程
        Console.WriteLine("主线程结束");
    }
    
    static void WorkWithSleep(int threadNum)
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"{Thread.CurrentThread.Name}: 执行步骤 {i + 1} - {DateTime.Now:HH:mm:ss.fff}");
            
            // 不同线程有不同的休眠时间
            Thread.Sleep(threadNum * 500);
        }
        Console.WriteLine($"{Thread.CurrentThread.Name}: 完成所有任务");
    }
}

案例3:Task.Delay异步等待

using System;
using System.Threading.Tasks;
using System.Diagnostics;

class TaskDelayDemo
{
    static async Task Main()
    {
        Console.WriteLine("开始异步等待演示");
        
        // 启动多个异步任务
        Task task1 = DelayedTaskAsync("任务1", 1000);
        Task task2 = DelayedTaskAsync("任务2", 2000);
        Task task3 = DelayedTaskAsync("任务3", 1500);
        
        Console.WriteLine("所有任务已启动,主线程继续执行...");
        
        // 等待所有任务完成
        await Task.WhenAll(task1, task2, task3);
        
        Console.WriteLine("所有异步任务完成");
    }
    
    static async Task DelayedTaskAsync(string taskName, int delayMs)
    {
        Console.WriteLine($"{taskName} 开始 - {DateTime.Now:HH:mm:ss.fff}");
        
        await Task.Delay(delayMs); // 异步等待
        
        Console.WriteLine($"{taskName} 完成 - {DateTime.Now:HH:mm:ss.fff}");
    }
}

案例4:Thread.Yield和SpinWait的使用

using System;
using System.Threading;
using System.Diagnostics;

class YieldAndSpinWaitDemo
{
    private static bool _flag = false;
    
    static void Main()
    {
        Console.WriteLine("Thread.Yield 演示:");
        YieldExample();
        
        Console.WriteLine("\nSpinWait 演示:");
        SpinWaitExample();
    }
    
    static void YieldExample()
    {
        Thread producer = new Thread(() =>
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine($"生产者: 生产项目 {i + 1}");
                Thread.Yield(); // 让出CPU时间片
            }
        });
        
        Thread consumer = new Thread(() =>
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine($"消费者: 消费项目 {i + 1}");
                Thread.Yield(); // 让出CPU时间片
            }
        });
        
        producer.Start();
        consumer.Start();
        
        producer.Join();
        consumer.Join();
    }
    
    static void SpinWaitExample()
    {
        _flag = false;
        
        // 启动设置标志的线程
        Thread setter = new Thread(() =>
        {
            Thread.Sleep(1000); // 模拟一些工作
            _flag = true;
            Console.WriteLine("标志已设置为 true");
        });
        
        // 启动等待标志的线程
        Thread waiter = new Thread(() =>
        {
            SpinWait spinWait = new SpinWait();
            while (!_flag)
            {
                spinWait.SpinOnce(); // 忙等待
            }
            Console.WriteLine("检测到标志变化,继续执行");
        });
        
        waiter.Start();
        setter.Start();
        
        waiter.Join();
        setter.Join();
    }
}

案例5:可中断的等待

using System;
using System.Threading;

class InterruptibleWaitDemo
{
    static void Main()
    {
        Thread workerThread = new Thread(InterruptibleWork);
        workerThread.Start();
        
        Console.WriteLine("按任意键中断线程等待...");
        Console.ReadKey();
        
        // 中断线程的等待
        workerThread.Interrupt();
        workerThread.Join();
        
        Console.WriteLine("程序结束");
    }
    
    static void InterruptibleWork()
    {
        try
        {
            Console.WriteLine("开始长时间等待...");
            Thread.Sleep(10000); // 等待10秒
            Console.WriteLine("等待完成");
        }
        catch (ThreadInterruptedException)
        {
            Console.WriteLine("等待被中断");
        }
    }
}

知识点总结

  1. Thread.Sleep(): 阻塞当前线程指定时间,适用于同步场景
  2. Task.Delay(): 异步等待,不阻塞线程,适用于异步方法
  3. Thread.Yield(): 主动让出CPU时间片,给其他线程执行机会
  4. SpinWait: 忙等待机制,适用于短时间等待,避免线程切换开销
  5. 可中断等待: 使用ThreadInterruptedException处理等待中断
  6. 性能考虑: 选择合适的等待方式对应用性能影响很大
  7. 最佳实践: 在异步环境中优先使用Task.Delay,在同步环境中使用Thread.Sleep
posted @ 2025-08-27 01:24  jessqiu  阅读(25)  评论(0)    收藏  举报