C# 自定义类型缓存对象,volatile和weakreference的引用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SingleInstanceDemo
{
    //断子绝孙的类
    public sealed class MyCacheItem<T> : IDisposable where T : class
    {
        private volatile T _value;
        //只能对类和结构的字段,使用这个关键字
        //将 volatile 修饰符添加到 _shouldStop 的声明后,将始终获得相同的结果
        //https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/volatile?f1url=%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(volatile_CSharpKeyword);k(TargetFrameworkMoniker-.NETFramework,Version%253Dv4.5);k(DevLang-csharp)%26rd%3Dtrue

        //初始化引用指定对象的 WeakReference<T> 类的新实例。
        //反正声明一种弱引用类型
        private WeakReference<T> _weakObject;

        //只读
        private readonly object _syncLock = new object();
        private long _expiration;
        private readonly bool _useWeakReference;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="value">缓存结果</param>
        /// <param name="expiration">缓存的过期时间,如果访问Value属性时【超过】过期时间,则返回结果类型的默认值</param>
        /// <param name="useWeakReference">是否允许使用弱引用来缓存对象</param>
        public MyCacheItem(T value, DateTime expiration, bool useWeakReference = true)
        {
            _useWeakReference = useWeakReference;
            SetValue(value, expiration);
        }

        private void SetValue(T value, DateTime expiration)
        {
            //设置值,明显多个线程也要都是使用这个缓存内容,否则出现脏数据bug
            lock (_syncLock)
            {
                //如果设置的值是null,那么对应的弱引用对象,和值都是null
                if (value == null)
                {
                    _value = null;
                    _weakObject = null;
                    //就是一个赋值操作,即让_expiration = DateTime.MinValue.Ticks;
                    //这里是线程安全的,即多个线程来操作,也能保证原子操作,都是同一个值,
                    Interlocked.Exchange(ref _expiration, DateTime.MinValue.Ticks);
                }
                //设置相关的值,和过期时间
                else
                {
                    //先判断是否采用弱引用,符合条件的情况指定过,
                    if (UseWeakReference(value, expiration))
                    {
                        //是弱引用,那么真实的值_value = null,
                        //采用弱引用方式,那么使用之前先判断,
                        // 防止开发人员缓存大对象,长时间运行会导致OOM,所以这里使用【弱引用】
                        _value = null;
                        _weakObject = new WeakReference<T>(value);
                    }
                    else
                    {
                        _value = value;
                        _weakObject = null;
                    }
                    Interlocked.Exchange(ref _expiration, expiration.Ticks);
                }
            }
        }

        private bool UseWeakReference(T value, DateTime expiration)
        {
            if (_useWeakReference == false)
                return false;

            // 永不过期的对象,不用弱引用保持
            if (expiration == DateTime.MaxValue)
                return false;


            // 【小字符串】,不用弱引用保持。 这里的【大/小】和GC的85K大对象不是一回事。
            if (typeof(T) == typeof(string) && ((string)(object)value).Length < 1024)
                return false;


            return true;
        }

        /// <summary>
        /// 修改缓存值
        /// </summary>
        /// <param name="value">缓存结果</param>
        /// <param name="expiration">过期时间</param>
        public void Set(T value, DateTime expiration)
        {
            SetValue(value, expiration);
        }

        /// <summary>
        /// 从缓存中获取结果
        /// </summary>
        /// <returns>已缓存的结果。如果缓存中不存在或者超过了过期时间,则返回结果类型的默认值</returns>
        public T Get()
        {
            //设置值,明显多个线程也要都是使用这个缓存内容,否则出现脏数据bug
            lock (_syncLock)
            {
                //存在这个强类型,
                if (_value != null)
                {
                    // 过期那么清除缓存自身这个对象,可以释放掉
                    if (IsExpired())
                    {
                        Dispose();    // 清除缓存引用(延迟清理)
                        return default(T);
                    }
                    //没有过期那么直接返回这个值,
                    else
                    {
                        return _value;
                    }
                }
                //如果弱类型不为空,那么前面的value可能为空,
                if (_weakObject != null)
                {
                    //过期都是返回默认值null
                    if (IsExpired())
                    {
                        Dispose();    // 清除缓存引用(延迟清理)
                        return default(T);
                    }
                    else
                    {
                        T data = default(T);
                        //输出弱引用的结果,
                        _weakObject.TryGetTarget(out data);
                        return data;
                    }
                }
            }
            return default(T);
        }
        //使用的时候,判断当前时间和过期时间关系,大于过期时间,即已经过期
        internal bool IsExpired()
        {
            return DateTime.Now.Ticks > Interlocked.Read(ref _expiration);
        }

        //
        //public MyCacheItem()
        //{

        //}

        public void Dispose()
        {
            //执行释放过程,同样保证多线程也是同步
            //不同的实例,即不同进程不用考虑,因为各自维护的静态变量不一致,
            lock (_syncLock)
            {
                //不为空,但是已经过期,
                if (_value != null)
                {
                    //可释放的对象,直接调用释放,
                    IDisposable disposable = _value as IDisposable;
                    disposable?.Dispose();

                    // 释放引用
                    _value = null;
                }
                //如果弱类型,存在
                if (_weakObject != null)
                {

                    T weakValue = default(T);
                    _weakObject.TryGetTarget(out weakValue);
                    //从弱引用中拿到当前缓存对象,

                    //释放当前缓存值,
                    if (weakValue != null)
                    {
                        IDisposable disposable = weakValue as IDisposable;
                        disposable?.Dispose();
                    }

                    // 释放弱引用自身引用,和弱引用的对象的引用
                    _weakObject.SetTarget(null);
                    _weakObject = null;
                }
            }
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值