zoukankan      html  css  js  c++  java
  • 【最佳实践】弱引用最佳实践——中介者模式

    前言:

      我们做Java一段时间的,或者刚入门的,通常都会被面试题耳濡目染一道题,Java的引用类型有:强应用,弱引用,软引用,虚引用,本文不对他们作介绍,因为你基本都能查得到,而且答案相差不多,将要提及的是他们的两种应用场景,第一种是大家都知道的:缓存场景,第二种是结合一种设计模式:中介者模式;

      其实还有一个值得一提的是,弱引用的类,一般是:

      软引用:发生full gc后,如果还是不足,那么就会回收软引用对象;

    SoftReference<byte[]> cacheRef = new SoftReference<>(cacheData);

      弱引用:弱引用是,只要触发GC,而且该引用没有其他强引用了,那必然回收弱引用

    WeakReference<byte[]> cacheRef = new WeakReference<>(cacheData);

      虚引用:虚引用是必然会被回收的,而且无法通过虚引用来获取一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。虚引用的get方法始终返回null。

      -----

    WeakHashMap:

      弱引用有一个很好用的数据结构,WeakHashMap,这个数据结构也是下文最佳实践的一个应用,当然,如果想要实现一个WeakhashSet的话,可以利用该Map去实现,因为该Map的弱引用是体现在key上面的;  

    Set<CacheData> requests = Collections.newSetFromMap(new WeakHashMap< CacheData, Boolean>());

      摘一段《Java核心技术卷》的话:

    设计 WeakHashMap类是为了解决一个有趣的问题。如果有一个值,对应的键已经不再 使用了, 将会出现什么情况呢? 假定对某个键的最后一次引用已经消亡,不再有任何途径引 用这个值的对象了。但是,由于在程序中的任何部分没有再出现这个键,所以,这个键 / 值 对无法从映射中删除。为什么垃圾回收器不能够删除它呢? 难道删除无用的对象不是垃圾回 收器的工作吗?

    遗憾的是,事情没有这样简单。垃圾回收器跟踪活动的对象。只要映射对象是活动的, 其中的所有桶也是活动的, 它们不能被回收。因此,需要由程序负责从长期存活的映射表中 删除那些无用的值。 或者使用 WeakHashMap完成这件事情。当对键的唯一引用来自散列条
    目时, 这一数据结构将与垃圾回收器协同工作一起删除键 / 值对。

    下面是这种机制的内部运行情况。WeakHashMap 使用弱引用(weak references) 保存键。 WeakReference 对象将引用保存到另外一个对象中,在这里,就是散列键。对于这种类型的 对象,垃圾回收器用一种特有的方式进行处理。通常,如果垃圾回收器发现某个特定的对象 已经没有他人引用了,就将其回收。然而, 如果某个对象只能由 WeakReference 引用, 垃圾 回收器仍然回收它,但要将引用这个对象的弱引用放人队列中。WeakHashMap将周期性地检 查队列, 以便找出新添加的弱引用。一个弱引用进人队列意味着这个键不再被他人使用, 并 且已经被收集起来。于是, WeakHashMap将删除对应的条目。 

      总结一下,如上文所述,如果一个key不再被除了这个长生命周期的Map之外的其他地方使用,那么就可以被垃圾回收回收key,并且把该key放入一个队列中,WeakHashMap周期性的去移除对应map中的key,value对,从而达到回收非弱引用的value对象,有趣的是,这个周期性,是在你调用该WeakHashMap的时候出发的,并非真正的周期性。

    最佳实践—缓存:

      缓存是一种比较有用的实现,在领域语义上,通常不会出现缓存的概念,缓存主要是计算机的概念,为了提供性能而实现的一种对领域透明的策略;因为内存也很宝贵,所以缓存一般会只缓存经常用的数据,而不用的就需要替换掉,于是有LRU和LFU这些算法出现,其中如果需要在内存中使用的话就用Google的Guava实现。

      通常缓存用弱引用的比较少,而用

    最佳实践—中介者模式:

      中介者模式,我用一句话来表示就是:解耦合消息的发送者A与接收者B,接耦的方式是在其中加入一个中介者M,中介者里面有一个核心的Map,或者词典,用来保存接收者的id和接收者的实际引用的影射关系,从而使得程序的消息发送中,A不需要耦合B的实现,使得类可以独立修改,即从代码耦合,变为数据耦合(id即为数据);

      当然有些中介者是不用Map的,而是用List,所以其实就喝观察者模式一样了

      数据耦合是最难解的耦合。

      中介者模式类图:

      我们注意到,这个中介者模式有一个特点:

      中介者的生命周期:Media的生命周期一般是长期的,也就是不会被回收,所以如果Map也是强引用,例如HashMap,那么就会出现即使ColleageA不会被继续使用,也会一直在内存中,从而导致内存泄露。

      所以中介者,必然要处理Colleage的生命周期,编程难度加大,所幸的是,Weak引用,正好可以用在这里,只要把ConcreteMedia的Map改为WeakHashMap,当外部没有再需要这个对象的时候,那么此刻垃圾回收器就会把中介者中的Map自动回收了。

      当然,回收时机是当你再次调用该Map的时候。

  • 相关阅读:
    POJ 1673
    POJ 1375
    POJ 1654
    POJ 1039
    POJ 1066
    UVA 10159
    POJ 1410
    POJ 2653
    POJ 2398
    POJ 1556
  • 原文地址:https://www.cnblogs.com/iCanhua/p/12828638.html
Copyright © 2011-2022 走看看