首页

分享apache的通过对象弱引用WeakReference实现的WeakHashtable实现Hashtable的优化源码解读

标签:WeakHashtable,弱引用,WeakReference,apache,commons-logging-optional     发布时间:2018-01-11   

一、前言

关于apache的源码包commons-logging-optional.jar.zip中提供了org.apache.commons.logging.impl.WeakHashtable弱引用自定义哈希表,其继承Hashtable并对保存对象的引用关系使用了WeakReference,对于大数据内存优化等场景提供更好的内存利用率。

二、源码说明

package org.apache.commons.logging.impl;@b@@b@import java.lang.ref.ReferenceQueue;@b@import java.lang.ref.WeakReference;@b@import java.util.Collection;@b@import java.util.Enumeration;@b@import java.util.HashSet;@b@import java.util.Hashtable;@b@import java.util.Iterator;@b@import java.util.Map;@b@import java.util.Map.Entry;@b@import java.util.Set;@b@@b@public final class WeakHashtable extends Hashtable@b@{@b@  private static final int MAX_CHANGES_BEFORE_PURGE = 100;@b@  private static final int PARTIAL_PURGE_COUNT = 10;@b@  private ReferenceQueue queue = new ReferenceQueue();@b@  private int changeCount = 0;@b@@b@  public boolean containsKey(Object key)@b@  {@b@    Referenced referenced = new Referenced(key, null);@b@    return super.containsKey(referenced);@b@  }@b@@b@  public Enumeration elements()@b@  {@b@    purge();@b@    return super.elements();@b@  }@b@@b@  public Set entrySet()@b@  {@b@    purge();@b@    Set referencedEntries = super.entrySet();@b@    Set unreferencedEntries = new HashSet();@b@    for (Iterator it = referencedEntries.iterator(); it.hasNext(); ) {@b@      Map.Entry entry = (Map.Entry)it.next();@b@      Referenced referencedKey = (Referenced)entry.getKey();@b@      Object key = Referenced.access$100(referencedKey);@b@      Object value = entry.getValue();@b@      if (key == null) break label94;@b@      Entry dereferencedEntry = new Entry(key, value, null);@b@      label94: unreferencedEntries.add(dereferencedEntry);@b@    }@b@@b@    return unreferencedEntries;@b@  }@b@@b@  public Object get(Object key)@b@  {@b@    Referenced referenceKey = new Referenced(key, null);@b@    return super.get(referenceKey);@b@  }@b@@b@  public Enumeration keys()@b@  {@b@    purge();@b@    Enumeration enumer = super.keys();@b@    return new Enumeration(this, enumer) { private final Enumeration val$enumer;@b@      private final WeakHashtable this$0;@b@@b@      public boolean hasMoreElements() { return this.val$enumer.hasMoreElements(); }@b@@b@      public Object nextElement() {@b@        WeakHashtable.Referenced nextReference = (WeakHashtable.Referenced)this.val$enumer.nextElement();@b@        return WeakHashtable.Referenced.access$100(nextReference);@b@      }@b@    };@b@  }@b@@b@  public Set keySet()@b@  {@b@    purge();@b@    Set referencedKeys = super.keySet();@b@    Set unreferencedKeys = new HashSet();@b@    for (Iterator it = referencedKeys.iterator(); it.hasNext(); ) {@b@      Referenced referenceKey = (Referenced)it.next();@b@      Object keyValue = Referenced.access$100(referenceKey);@b@      if (keyValue == null) break label59;@b@      label59: unreferencedKeys.add(keyValue);@b@    }@b@@b@    return unreferencedKeys;@b@  }@b@@b@  public Object put(Object key, Object value)@b@  {@b@    if (key == null)@b@      throw new NullPointerException("Null keys are not allowed");@b@@b@    if (value == null) {@b@      throw new NullPointerException("Null values are not allowed");@b@    }@b@@b@    if (this.changeCount++ > 100) {@b@      purge();@b@      this.changeCount = 0;@b@    }@b@    else if (this.changeCount % 10 == 0) {@b@      purgeOne();@b@    }@b@@b@    Object result = null;@b@    Referenced keyRef = new Referenced(key, this.queue, null);@b@    return super.put(keyRef, value);@b@  }@b@@b@  public void putAll(Map t)@b@  {@b@    if (t != null) {@b@      Set entrySet = t.entrySet();@b@      for (Iterator it = entrySet.iterator(); it.hasNext(); ) {@b@        Map.Entry entry = (Map.Entry)it.next();@b@        put(entry.getKey(), entry.getValue());@b@      }@b@    }@b@  }@b@@b@  public Collection values()@b@  {@b@    purge();@b@    return super.values();@b@  }@b@@b@  public Object remove(Object key)@b@  {@b@    if (this.changeCount++ > 100) {@b@      purge();@b@      this.changeCount = 0;@b@    }@b@    else if (this.changeCount % 10 == 0) {@b@      purgeOne();@b@    }@b@    return super.remove(new Referenced(key, null));@b@  }@b@@b@  public boolean isEmpty()@b@  {@b@    purge();@b@    return super.isEmpty();@b@  }@b@@b@  public int size()@b@  {@b@    purge();@b@    return super.size();@b@  }@b@@b@  public String toString()@b@  {@b@    purge();@b@    return super.toString();@b@  }@b@@b@  protected void rehash()@b@  {@b@    purge();@b@    super.rehash();@b@  }@b@@b@  private void purge()@b@  {@b@    synchronized (this.queue)@b@    {@b@      WeakKey key;@b@      while ((key = (WeakKey)this.queue.poll()) != null) {@b@        WeakKey localWeakKey1;@b@        super.remove(WeakKey.access$400(localWeakKey1));@b@      }@b@    }@b@  }@b@@b@  private void purgeOne()@b@  {@b@    synchronized (this.queue) {@b@      WeakKey key = (WeakKey)this.queue.poll();@b@      if (key != null)@b@        super.remove(WeakKey.access$400(key));@b@    }@b@  }@b@@b@  private static final class WeakKey extends WeakReference@b@  {@b@    private final WeakHashtable.Referenced referenced;@b@@b@    private WeakKey(Object key, ReferenceQueue queue, WeakHashtable.Referenced referenced)@b@    {@b@      super(key, queue);@b@      this.referenced = referenced;@b@    }@b@@b@    private WeakHashtable.Referenced getReferenced() {@b@      return this.referenced;@b@    }@b@@b@    static WeakHashtable.Referenced access$400(WeakKey x0)@b@    {@b@      return x0.getReferenced(); } @b@    WeakKey(Object x0, ReferenceQueue x1, WeakHashtable.Referenced x2, WeakHashtable.1 x3) { this(x0, x1, x2);@b@    }@b@  }@b@@b@  private static final class Referenced@b@  {@b@    private final WeakReference reference;@b@    private final int hashCode;@b@@b@    private Referenced(Object referant)@b@    {@b@      this.reference = new WeakReference(referant);@b@@b@      this.hashCode = referant.hashCode();@b@    }@b@@b@    private Referenced(Object key, ReferenceQueue queue)@b@    {@b@      this.reference = new WeakHashtable.WeakKey(key, queue, this, null);@b@@b@      this.hashCode = key.hashCode();@b@    }@b@@b@    public int hashCode()@b@    {@b@      return this.hashCode;@b@    }@b@@b@    private Object getValue() {@b@      return this.reference.get();@b@    }@b@@b@    public boolean equals(Object o) {@b@      boolean result = false;@b@      if (o instanceof Referenced) {@b@        Referenced otherKey = (Referenced)o;@b@        Object thisKeyValue = getValue();@b@        Object otherKeyValue = otherKey.getValue();@b@        if (thisKeyValue == null) {@b@          result = otherKeyValue == null;@b@@b@          if (result == true) {@b@            result = hashCode() == otherKey.hashCode();@b@          }@b@@b@        }@b@        else@b@        {@b@          result = thisKeyValue.equals(otherKeyValue);@b@        }@b@      }@b@      return result;@b@    }@b@@b@    Referenced(Object x0, WeakHashtable.1 x1)@b@    {@b@      this(x0); } @b@    static Object access$100(Referenced x0) { return x0.getValue(); } @b@    Referenced(Object x0, ReferenceQueue x1, WeakHashtable.1 x2) { this(x0, x1);@b@    }@b@  }@b@@b@  private static final class Entry@b@    implements Map.Entry@b@  {@b@    private final Object key;@b@    private final Object value;@b@@b@    private Entry(Object key, Object value)@b@    {@b@      this.key = key;@b@      this.value = value;@b@    }@b@@b@    public boolean equals(Object o) {@b@      boolean result = false;@b@      if ((o != null) && (o instanceof Map.Entry)) {@b@        Map.Entry entry = (Map.Entry)o;@b@        if (getKey() == null) if (entry.getKey() != null) break label92; @b@        else if (!(getKey().equals(entry.getKey()))) break label92; @b@        if (getValue() == null) if (entry.getValue() != null) break label92; @b@        label92: result = getValue().equals(entry.getValue());@b@      }@b@@b@      return result;@b@    }@b@@b@    public int hashCode()@b@    {@b@      return (((getKey() == null) ? 0 : getKey().hashCode()) ^ ((getValue() == null) ? 0 : getValue().hashCode()));@b@    }@b@@b@    public Object setValue(Object value)@b@    {@b@      throw new UnsupportedOperationException("Entry.setValue is not supported.");@b@    }@b@@b@    public Object getValue() {@b@      return this.value;@b@    }@b@@b@    public Object getKey() {@b@      return this.key;@b@    }@b@@b@    Entry(Object x0, Object x1, WeakHashtable.1 x2)@b@    {@b@      this(x0, x1);@b@    }@b@  }@b@}