Static ConcurrentDictionary to maintain static objects I am using following code to maintain some static information. The problem I see with it is that, if the information retrieved using GeKeysFromCache is modified without using lock keyword it may lead to exceptions in a multithreaded environment. Is there a way to improve this implementation?

public class CacheHelper
{
    private static ConcurrentDictionary&lt;string, List&lt;InstanceField&gt;&gt; m_InstancesCached = new ConcurrentDictionary&lt;string, List&lt;InstanceField&gt;&gt;();
    private static readonly Object _entriesLock = new object();

    public List&lt;InstanceField&gt; GeKeysFromCache(string cacheKey)
    {
        return m_InstancesCached.GetOrAdd(cacheKey, (key) =&gt;
        {
            return new List&lt;InstanceField&gt;();
        });
    }

    public void AddKeysToCache(string cacheKey, List&lt;InstanceField&gt; inputs)
    {
        m_InstancesCached.AddOrUpdate(cacheKey, inputs, (key, oldValue) =&gt;
        {
            lock (_entriesLock)
            {
                oldValue.AddRange(inputs);
                return oldValue;
            }
        });
    }
}


Test Code: Without lock keyword it fails

public class ThreadSafeCachingTest
{
    private static readonly Object _entriesLock = new object();
    public ThreadSafeCachingTest()
    {
    }

    public void Invoke()
    {
        var thread1Completed = false;
        var thread2Completed = false;
        var thread3Completed = false;
        var threadList = new List&lt;Thread&gt;();

        var instanceName = "MyInstance";
        var beforeCachingData = (new CacheHelper()).GeKeysFromCache(instanceName);

        threadList.Add(new Thread(() =&gt;
        {
            //lock (_entriesLock)
            //{
            var instanceFields1 = (new CacheHelper()).GeKeysFromCache(instanceName);
            instanceFields1 = instanceFields1 ?? new List&lt;InstanceField&gt;();

            for (int i = 0; i &lt; 10000; i++)
            {
                instanceFields1.Add(new InstanceField() { FieldName = "FieldName-" + i.ToString() });
            }
            thread1Completed = true;
            //}
        }));


        threadList.Add(new Thread(() =&gt;
        {
            //lock (_entriesLock)
            //{
            var instanceFields2 = (new CacheHelper()).GeKeysFromCache(instanceName);
            instanceFields2 = instanceFields2 ?? new List&lt;InstanceField&gt;();

            for (int i = 10000; i &lt; 20000; i++)
            {
                instanceFields2.Add(new InstanceField() { FieldName = "FieldName-" + i.ToString() });
            }
            thread2Completed = true;
            //}
        }));

        threadList.Add(new Thread(() =&gt;
        {
            //lock (_entriesLock)
            //{
            while (!(thread1Completed &amp;&amp; thread2Completed &amp;&amp; thread3Completed))
            {
                var instanceFields3 = (new CacheHelper()).GeKeysFromCache(instanceName);
                if (instanceFields3.Count &gt; 0)
                {
                    instanceFields3.RemoveAt(0);
                }
                else
                {
                    thread3Completed = true;
                }
                //}
            }
        }));

        foreach (Thread t in threadList) t.Start();
        foreach (Thread t in threadList) t.Join();

        var afterCachingData = (new CacheHelper()).GeKeysFromCache(instanceName);
    }
}

public class InstanceField
{
    public string FieldName { get; set; }
}
public List&lt;InstanceField&gt; GeKeysFromCache(string cacheKey)
{
    var resultSet = m_InstancesCached.GetOrAdd(cacheKey, (key) =&gt;
   {
       return new List&lt;InstanceField&gt;();
   });

    return resultSet.ToList();
}



Why so many returns and when you can simply do this with only one return and without the lambda:

return m_InstancesCached.GetOrAdd(cacheKey, new List&lt;string&gt;()).ToList();