四 C# 多线程研究 Monitor和lock用法举例

本文介绍了多线程环境下如何使用锁机制确保代码段或对象的安全访问。通过两个实例演示了如何利用lock和Monitor实现线程间的同步,强调了单例模式和全局对象在资源安全共享中的作用。

  这两个对象一般用于锁定一段代码,或者锁定一个对象。下面举两个例子予以说明:

  1:锁定代码

ContractedBlock.gifExpandedBlockStart.gifCode
using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;
using System.Reflection;

namespace ThreadLock
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Thread t1 
= new Thread(new ThreadStart(threadMethod1));
            Thread t2 
= new Thread(new ThreadStart(threadMethod2));
            t1.IsBackground 
= true;
            t2.IsBackground 
= true;
            t1.Start();
            t2.Start();

            Console.ReadLine();
        }


        
static void threadMethod1()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            A a 
= A.GetInstance();
            
while (true)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                a.print(
1);
                Thread.Sleep(
1000);
            }

        }


        
static void threadMethod2()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            A a 
= A.GetInstance();
            
while (true)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                a.print(
2);
                Thread.Sleep(
1000);
            }

        }

    }


    
class A
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
private static A _instance = null;

        
private A()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
        }


        
public static A GetInstance()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_instance == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _instance 
= new A();
            }

            
return _instance;
        }


        
public void print(int a)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
lock (_instance)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(a.ToString());
                Thread.Sleep(
5000);
            }

        }

    }

}

  print(int a)中的代码被lock锁定,两个线程便只能依次访问这段代码,注意这里的类A是单例,这样是为了lock锁住的都是同一个对象。这里的lock也可以用Monitor对象来代替:  

public void print(int a)
ExpandedBlockStart.gifContractedBlock.gif        
{
            Monitor.Enter(
_instance);
            Console.WriteLine(a.ToString());
            Monitor.Exit(
_instance);
        }

  此时,一直锁定这段代码(即去掉Monitor.Exit(this)),结果将会很有趣:要么线程1一直占据这段代码的控制权,屏幕上一直输出1;要么线程2一直占据,一直输出2。由此可见:在单例模式下,不同线程中创建的不同对象,是可以通过在单例对象内部锁定一个函数来达到资源安全共享的目的。

  Monitor只有在多线程的情况下才使用,否则,如果只有一个线程,会报错。

  2:锁定对象

  如果将threadMethod1()改成如下:

        static void threadMethod1()
ExpandedBlockStart.gifContractedBlock.gif        
{
            A a 
= A.GetInstance();
            
lock (a)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
while (true)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    a.print(
1);
                    Thread.Sleep(
1000);
                }

            }

        }

    此时,屏幕上并不会一直只打印1,而是1和2几乎一起打印(print()方法中不加任何锁)。这是因为在线程1中锁定的a对象,和线程2中的a对象的指向不相同,因此线程1即使锁定了a对象,也无法阻挡线程2访问print()方法。如果要线程1一直占据对a的控制权,只能全局定义一个a对象,让线程1和线程2共享这个对象,此时线程1的锁才有意义。

  由此可见,如果两个线程在外部锁定一个对象,则这两个线程中的对象必须是同一个对象,此时可以在主线程中声明一个全局对象让多线程共享。

 

  总之,通过上面的实验,可以看出:在多线程中,要想锁定一段代码,必须使得调用方在调用对象的该段代码所在的方法时,两个线程中的对象必须是同一个对象。在外部锁定一个对象时,也必须保证两个线程中所锁定的对象是同一个对象,否则,锁将失去意义。通过单例模式或者全局声明对象,可以有效实现资源共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值