0

0

C#的Monitor类和lock语句有何关系?

煙雲

煙雲

发布时间:2025-08-01 09:37:01

|

190人浏览过

|

来源于php中文网

原创

c#的monitor类和lock语句有何关系?

C#中的Monitor类和lock语句实际上是同一概念的不同表达方式。lock语句是Monitor类的语法糖,提供了一种更简洁、易用的方式来获取和释放对象的互斥锁。

lock语句本质上是Monitor.Enter和Monitor.Exit的封装。

// lock 语句
lock (obj)
{
  // 受保护的代码
}

// 等价于
Monitor.Enter(obj);
try
{
  // 受保护的代码
}
finally
{
  Monitor.Exit(obj);
}

lock语句保证了即使在受保护的代码块中发生异常,锁也会被正确释放,避免死锁。

C# Monitor类的核心功能是什么?

Monitor类提供了一系列静态方法,用于实现线程同步,它允许线程获取对象的独占锁,并提供了线程等待和通知机制。主要功能包括:

  • Enter(object obj): 获取指定对象的独占锁。如果锁已经被其他线程持有,当前线程会阻塞,直到锁被释放。
  • TryEnter(object obj): 尝试获取指定对象的独占锁。如果锁可用,则获取锁并返回true;否则,立即返回false,不会阻塞。TryEnter还有带超时时间的重载版本,允许线程等待一段时间。
  • Exit(object obj): 释放指定对象的独占锁。必须与Enter配对使用。
  • Wait(object obj): 释放对象的锁,并阻塞当前线程,直到其他线程调用PulsePulseAll来唤醒它。必须在持有锁的情况下调用。
  • Pulse(object obj): 通知等待队列中的一个线程,使其变为就绪状态。必须在持有锁的情况下调用。
  • PulseAll(object obj): 通知等待队列中的所有线程,使其变为就绪状态。必须在持有锁的情况下调用。

使用Monitor类时,需要特别注意锁的正确释放。如果忘记调用Exit,或者在EnterExit之间发生未处理的异常,可能会导致死锁。这也是为什么lock语句更安全的原因,因为它使用try-finally块来确保锁总是被释放。

什么时候应该使用Monitor类而不是lock语句?

虽然lock语句在大多数情况下更方便、更安全,但Monitor类在某些高级场景下提供了更大的灵活性。例如:

  • 需要尝试获取锁,而不是无限期阻塞:可以使用Monitor.TryEnter方法。这在某些需要避免长时间阻塞的场景中很有用。
  • 需要更精细的控制线程同步Monitor类的WaitPulsePulseAll方法提供了线程等待和通知机制,可以实现更复杂的线程同步逻辑,例如生产者-消费者模式。
  • 在某些特殊情况下,需要手动管理锁的生命周期:虽然不推荐,但在某些特定的性能优化场景下,可能需要手动控制锁的获取和释放。

一个使用Monitor类实现简单线程同步的例子:

Python开发网站指南 WORD版
Python开发网站指南 WORD版

本文档主要讲述的是Python开发网站指南;HTML是网络的通用语言,一种简单、通用的全置标记语言。它允许网页制作人建立文本与图片相结合的复杂页面,这些页面可以被网上任何其他人浏览到,无论使用的是什么类型的电脑或浏览器 Python和其他程序语言一样,有自身的一套流程控制语句,而且这些语句的语法和其它程序语言类似,都有for, if ,while 类的关键字来表达程序流程。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看

下载
class Example
{
    private static readonly object _locker = new object();
    private static int _counter = 0;

    public static void IncrementCounter()
    {
        Monitor.Enter(_locker);
        try
        {
            _counter++;
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: Counter = {_counter}");
        }
        finally
        {
            Monitor.Exit(_locker);
        }
    }

    public static void Main(string[] args)
    {
        Thread[] threads = new Thread[5];
        for (int i = 0; i < 5; i++)
        {
            threads[i] = new Thread(IncrementCounter);
            threads[i].Start();
        }

        foreach (Thread thread in threads)
        {
            thread.Join();
        }

        Console.WriteLine($"Final Counter Value: {_counter}");
    }
}

在这个例子中,多个线程同时访问和修改_counter变量。使用Monitor.EnterMonitor.Exit确保了对_counter的访问是线程安全的。try-finally块保证了即使在IncrementCounter方法中发生异常,锁也会被释放。

Monitor类的Wait(), Pulse(), PulseAll()方法具体如何使用?

WaitPulsePulseAllMonitor类中用于线程间通信的关键方法,它们允许线程在特定条件下挂起自身,等待其他线程发出信号。以下是它们的具体用法:

  • Wait(object obj):

    • 作用:释放指定对象的锁,并阻塞当前线程。线程会进入对象的等待队列,等待其他线程调用PulsePulseAll来唤醒它。
    • 使用场景:当线程需要等待某个条件满足时,可以使用Wait方法。例如,在生产者-消费者模式中,当缓冲区为空时,消费者线程可以调用Wait方法挂起自身,等待生产者线程向缓冲区添加数据。
    • 注意事项Wait方法必须在持有锁的情况下调用。调用Wait方法会自动释放锁,允许其他线程访问共享资源。当线程被唤醒后,它会尝试重新获取锁。
  • Pulse(object obj):

    • 作用:通知等待队列中的一个线程,使其变为就绪状态。被通知的线程会从等待队列中移除,并尝试重新获取锁。
    • 使用场景:当某个条件变为真时,可以使用Pulse方法通知等待该条件的线程。例如,在生产者-消费者模式中,当生产者线程向缓冲区添加数据后,可以调用Pulse方法唤醒一个等待的消费者线程。
    • 注意事项Pulse方法必须在持有锁的情况下调用。Pulse方法只会唤醒一个线程,如果有多个线程在等待,只有其中一个会被唤醒。
  • PulseAll(object obj):

    • 作用:通知等待队列中的所有线程,使其变为就绪状态。所有被通知的线程都会从等待队列中移除,并尝试重新获取锁。
    • 使用场景:当某个条件发生变化,可能影响到所有等待的线程时,可以使用PulseAll方法。例如,在某些复杂的并发场景中,可能需要一次性唤醒所有等待的线程。
    • 注意事项PulseAll方法必须在持有锁的情况下调用。PulseAll方法会唤醒所有等待的线程,这可能会导致竞争,因此需要谨慎使用。

一个使用WaitPulse实现生产者-消费者模式的例子:

class ProducerConsumer
{
    private static readonly object _locker = new object();
    private static Queue _queue = new Queue();
    private static int _capacity = 5;

    public static void Produce()
    {
        Random random = new Random();
        while (true)
        {
            lock (_locker)
            {
                while (_queue.Count == _capacity)
                {
                    Console.WriteLine("Producer is waiting, queue is full.");
                    Monitor.Wait(_locker);
                }

                int item = random.Next(100);
                _queue.Enqueue(item);
                Console.WriteLine($"Producer produced: {item}");
                Monitor.Pulse(_locker); // 通知一个消费者
            }

            Thread.Sleep(random.Next(500));
        }
    }

    public static void Consume()
    {
        Random random = new Random();
        while (true)
        {
            lock (_locker)
            {
                while (_queue.Count == 0)
                {
                    Console.WriteLine("Consumer is waiting, queue is empty.");
                    Monitor.Wait(_locker);
                }

                int item = _queue.Dequeue();
                Console.WriteLine($"Consumer consumed: {item}");
                Monitor.Pulse(_locker); // 通知一个生产者
            }

            Thread.Sleep(random.Next(500));
        }
    }

    public static void Main(string[] args)
    {
        Thread producerThread = new Thread(Produce);
        Thread consumerThread = new Thread(Consume);

        producerThread.Start();
        consumerThread.Start();

        Console.ReadKey();
    }
}

在这个例子中,生产者线程负责向队列中添加数据,消费者线程负责从队列中取出数据。当队列满时,生产者线程会调用Monitor.Wait挂起自身,等待消费者线程消费数据。当队列为空时,消费者线程会调用Monitor.Wait挂起自身,等待生产者线程生产数据。Monitor.Pulse用于通知等待的线程。

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

PHP 高并发与性能优化
PHP 高并发与性能优化

本专题聚焦 PHP 在高并发场景下的性能优化与系统调优,内容涵盖 Nginx 与 PHP-FPM 优化、Opcode 缓存、Redis/Memcached 应用、异步任务队列、数据库优化、代码性能分析与瓶颈排查。通过实战案例(如高并发接口优化、缓存系统设计、秒杀活动实现),帮助学习者掌握 构建高性能PHP后端系统的核心能力。

99

2025.10.16

PHP 数据库操作与性能优化
PHP 数据库操作与性能优化

本专题聚焦于PHP在数据库开发中的核心应用,详细讲解PDO与MySQLi的使用方法、预处理语句、事务控制与安全防注入策略。同时深入分析SQL查询优化、索引设计、慢查询排查等性能提升手段。通过实战案例帮助开发者构建高效、安全、可扩展的PHP数据库应用系统。

86

2025.11.13

JavaScript 性能优化与前端调优
JavaScript 性能优化与前端调优

本专题系统讲解 JavaScript 性能优化的核心技术,涵盖页面加载优化、异步编程、内存管理、事件代理、代码分割、懒加载、浏览器缓存机制等。通过多个实际项目示例,帮助开发者掌握 如何通过前端调优提升网站性能,减少加载时间,提高用户体验与页面响应速度。

25

2025.12.30

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

10

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

29

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

13

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.4万人学习

C 教程
C 教程

共75课时 | 4.2万人学习

C++教程
C++教程

共115课时 | 13.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号