如何在多线程环境中只执行一次代码块?

Posted

技术标签:

【中文标题】如何在多线程环境中只执行一次代码块?【英文标题】:How to execute a block of code only once on a multithreading environment? 【发布时间】:2021-11-25 23:22:16 【问题描述】:

以下代码块在 C# 中执行对象的加载。

public bool IsModelLoaded  get; set; 
public override MyObject Load()

    if (!IsModelLoaded)
    
        Model = MyService.LoadMyObject(Model);
        IsModelLoaded = true;
    
    return Model;

我的意图是只运行一次这个块,因此只加载一次Model。然而,这个代码块从 2 个不同的线程运行了两次。

如何确保此块只运行一次? (在多个线程上)。

【问题讨论】:

【参考方案1】:

使用Lazy<T> Class:

private readonly Lazy<MyObject> myObject;

public MyClass()

    myObject = new Lazy<MyObject>(() =>
    
        return MyService.LoadMyObject();
    , LazyThreadSafetyMode.ExecutionAndPublication);


public bool IsModelLoaded

    get  return myObject.IsValueCreated; 


public override MyObject Load()

    return myObject.Value;

【讨论】:

【参考方案2】:

最简单的就是添加

[MethodImpl(MethodImplOptions.Synchronized)]
public override MyObject Load()

   //snip

但请注意,这会锁定整个对象,而不仅仅是方法。不是很好的做法。

http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions.aspx

同步

指定该方法一次只能由一个线程执行。静态方法锁定类型,而实例方法锁定实例。任何实例函数中只能有一个线程执行,类的任何静态函数中只能有一个线程执行。

【讨论】:

【参考方案3】:

我正在尝试实现singleton 模式。但是您的版本不是线程安全的。在此处阅读更多信息:http://www.dofactory.com/Patterns/PatternSingleton.aspx。尝试使用此实现:

public sealed class Singleton

    static Singleton instance=null;
    static readonly object padlock = new object();

    Singleton()
    
    

    public static Singleton Instance
    
        get
        
            lock (padlock)
            
                if (instance==null)
                
                    instance = new Singleton();
                
                return instance;
            
        
    

【讨论】:

【参考方案4】:

如果你想编写线程安全的代码并确保块只运行一次,你可以这样写:

private System.Object lockThis = new System.Object(); 
public override MyObject Load()

    lock (lockThis) 
        if (!IsModelLoaded)
        
            Model = MyService.LoadMyObject(Model);
            IsModelLoaded = true;
        
    
    return Model;

【讨论】:

【参考方案5】:
Action myCodeBlock = ()=>

  //do your job
  //...
  myCodeBlock = ()=>;

在调用myCodeBlock() 一次后,它将被什么都不做的方法重写。您仍然需要确保安全地调用此方法 - 使用 lock 或其他。

【讨论】:

【参考方案6】:

您可以使用lock Statement (C# Reference)

【讨论】:

【参考方案7】:

创建一个静态对象(如布尔值),通过将其放入 if 语句中来确定代码是否已运行 :)

编辑:我不确定这是否是线程安全的,所以它可能不是你的解决方案。

【讨论】:

以上是关于如何在多线程环境中只执行一次代码块?的主要内容,如果未能解决你的问题,请参考以下文章

单例在多线程中的使用

如何在多线程环境下实现FIFO队列?

java如何在多线程执行完后才执行其他任务

如何使用 Java 在多线程环境中测试某些东西 [重复]

java - 如何在java中将特定数量的线程限制为同步块

如何在多线程环境中生成 PreparedStatements?