This cache is like a list where new elements are inserted in the middle, cache hits are put to head of the list and replaced elements are taken from the end. Would I just use a list the lookup would take O(n). With a dictionary it is O(log(n)) but I lose the order of elements, so I use both..Net but only has ConcurrentDictionary but not a ConcurrentList so I did not mix it with a List. Even read access would end in a write (cache hit) so I just use a lock in every method. How could I achieve something like multiple reader - one writer locking?using System;using System.Collections.Generic;using System.Diagnostics;namespace Bodhi{    /// <summary>    /// Simple threadsafe caching collection    /// </summary>    /// <typeparam name=TKey>Key of the cached item implementing IComparable</typeparam>    /// <typeparam name=TItem>Cached item</typeparam>    public class BodhiCache<TKey, TItem>        where TKey : IComparable        where TItem : class    {        /// <summary>        /// Initializes a new instance of BodhiCache.        /// </summary>        /// <param name=capacity>Capacity, default 1024</param>        public BodhiCache(int capacity = 1024)        {            this.Capacity = capacity;            m_keyOrder = new List<TKey>(this.Capacity);            m_cache = new Dictionary<TKey, TItem>(this.Capacity);        }        public int Capacity { get; private set; }        /// <summary>        /// Returns the current cache content including keys and items.        /// </summary>        public Dictionary<TKey, TItem> Content        {            get            {                lock (m_syncRoot)                {                    return new Dictionary<TKey, TItem>(m_cache);                }            }        }        /// <summary>        /// Gets the current number of cached items        /// </summary>        public int Count        {            get { return m_keyOrder.Count; }        }        /// <summary>        /// Clears the cache. Get the content before hand to implement a cache flush.        /// </summary>        public void Clear()        {            lock (m_syncRoot)            {                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);                m_cache.Clear();                m_keyOrder.Clear();                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);            }        }        /// <summary>        /// Invalidate a cache item by key        /// </summary>        /// <param name=key></param>        public void Invalidate(TKey key)        {            lock (m_syncRoot)            {                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);                m_keyOrder.Remove(key);                m_cache.Remove(key);                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);            }        }        /// <summary>        /// Get a cached item by key        /// </summary>        /// <param name=key></param>        /// <returns>Returns cached item if found, null otherwise</returns>        public TItem Load(TKey key)        {            lock (m_syncRoot)            {                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);                TItem result = null;                if (m_cache.ContainsKey(key) == true) // hit                {                    m_keyOrder.Remove(key);                    m_keyOrder.Add(key);                    result = m_cache[key];                    Debug.Assert(m_keyOrder[m_keyOrder.Count - 1].CompareTo(key) == 0);                }                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);                return result;            }        }        /// <summary>        /// Store an item by its key in the cache. For write-back you have to implement it with the        /// replaced item.        /// </summary>        /// <param name=key></param>        /// <param name=item></param>        /// <returns>Returns a replaced item if cache is full, null otherwise</returns>        public TItem Store(TKey key, TItem item)        {            Debug.Assert(m_keyOrder.Count == m_cache.Count);            Debug.Assert(m_keyOrder.Count <= this.Capacity);            lock (m_syncRoot)            {                m_insertIndex = m_keyOrder.Count / 2;                TItem old = null;                // refresh                if (m_cache.ContainsKey(key) == true)                {                    m_cache[key] = item;                    m_keyOrder.Remove(key);                    m_keyOrder.Insert(m_insertIndex, key);                }                else if (m_cache.Count == this.Capacity) // replacement                {                    // remove old                    var oldKey = m_keyOrder[0];                    m_keyOrder.RemoveAt(0);                    old = m_cache[oldKey];                    bool found = m_cache.Remove(oldKey);                    Debug.Assert(found == true);                    m_cache[key] = item;                    m_keyOrder.Insert(m_insertIndex, key);                }                else                {                    m_cache[key] = item;                    m_keyOrder.Insert(m_insertIndex, key);                }                Debug.Assert(m_keyOrder.Count == m_cache.Count);                Debug.Assert(m_keyOrder.Count <= this.Capacity);                return old;            }        }        private readonly object m_syncRoot = new object();        private Dictionary<TKey, TItem> m_cache;        private int m_insertIndex;        private List<TKey> m_keyOrder;    }}Cache strategy rationale: The insertion of new elements in the middle rates the new item higher than the lower half of older or low performing cache items. It would be possible to insert in the higher third or lower sixth.         You can find the improved version here while I am adding and testing the suggested ideas from here.                                                                                                                                                                                                                                                                                                                                                                                                          
Thread safe cache for write through and writeback
c#;reinventing the wheel;thread safety;cache;collections
The first thing I noticed (beside the things @RubberDuck mentioned) is that you compare with true for non nullable booleans, which is unnecessary.if (m_cache.ContainsKey(key) == true)   ...    Debug.Assert(found == true);Here are my two cents worth for a possible solution to your problem.If you create a class which looks like this, you can use a ConcurrentDictionary<CacheKey, TItem>.public class CacheKey<TKey>    where TKey : IComparable{    public DateTime DateAdded;    public int HitCount;    public TKey Key;}This may take a (small?) performance hit when you need to find out the oldest with the lowest hit count, depending on the size, but it will be thread safe.For example:var dictionary = new ConcurrentDictionary<CacheKey<string>, string>();/* adding stuff */var key = dic.Keys.OrderByDescending(p => p.HitCount)                  .ThenByDescending(p => p.DateAdded)                  .First();string value;dic.TryRemove(key, out value);I hope it will at least get you a little bit further.