﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-yuyee-随笔分类-缓存</title><link>http://www.blogjava.net/yuyee/category/46806.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 09 Nov 2010 10:02:23 GMT</lastBuildDate><pubDate>Tue, 09 Nov 2010 10:02:23 GMT</pubDate><ttl>60</ttl><item><title>linkedhashmap看看</title><link>http://www.blogjava.net/yuyee/archive/2010/11/08/337579.html</link><dc:creator>羔羊</dc:creator><author>羔羊</author><pubDate>Mon, 08 Nov 2010 15:14:00 GMT</pubDate><guid>http://www.blogjava.net/yuyee/archive/2010/11/08/337579.html</guid><description><![CDATA[linkedhashmap继承自hashmap,他的底层维护的一个链表，&nbsp;&nbsp; &nbsp;private transient Entry&lt;K,V&gt; header 来记录元素的插入顺序和访问顺序;
<div>hashmap的构造函数中调用init()方法，而linkedhashmap中重写了init(),将head元素初始化</div>
<div>
<div>&nbsp;&nbsp; void init() {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;header = new Entry&lt;K,V&gt;(-1, null, null, null);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;header.before = header.after = header;</div>
<div>&nbsp;&nbsp; &nbsp;}</div>
</div>
<div><br />
</div>
<div>private final boolean accessOrder这个属性表示是否要根据访问顺序改变线性结构</div>
<div>在linkedhashmap中改写了hashmap的get()方法，增加了&nbsp;e.recordAccess(this)，这个方法主要是根据accessOrder的值判断是否需要实现LRU，</div>
<div>
<div>&nbsp;void recordAccess(HashMap&lt;K,V&gt; m) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LinkedHashMap&lt;K,V&gt; lm = (LinkedHashMap&lt;K,V&gt;)m;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (lm.accessOrder) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lm.modCount++;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;remove();</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;addBefore(lm.header);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div>
</div>
<div><br />
</div>
<div>addBefore这个方法是把刚访问的元素放到head的前面</div>
<div>
<div>&nbsp;private void addBefore(Entry&lt;K,V&gt; existingEntry) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;after &nbsp;= existingEntry;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;before = existingEntry.before;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;before.after = this;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;after.before = this;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div>
</div>
<div>put方法继承自hashmap,hashmap预留了&nbsp;e.recordAccess(this)这个方法：</div>
<div>
<div>&nbsp;&nbsp;&nbsp; &nbsp;public V put(K key, V value) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (key == null)</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return putForNullKey(value);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;int hash = hash(key.hashCode());</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;int i = indexFor(hash, table.length);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;for (Entry&lt;K,V&gt; e = table[i]; e != null; e = e.next) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Object k;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (e.hash == hash &amp;&amp; ((k = e.key) == key || key.equals(k))) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;V oldValue = e.value;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;e.value = value;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;e.recordAccess(this);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return oldValue;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div>
<div><br />
</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;modCount++;</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;addEntry(hash, key, value, i);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return null;</div>
<div>&nbsp;&nbsp; &nbsp;}</div>
</div>
<div><br />
</div>
<div>并通过重写&nbsp;addEntry(hash, key, value, i)这个方法，实现LRU中的删除动作：</div>
<div>
<div>&nbsp;&nbsp; &nbsp;void addEntry(int hash, K key, V value, int bucketIndex) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;createEntry(hash, key, value, bucketIndex);</div>
<div><br />
</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// Remove eldest entry if instructed, else grow capacity if appropriate</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Entry&lt;K,V&gt; eldest = header.after;//找到最老的元素，这个在addBefore里确定，初次赋值是当只有一个head时候，你插入一个元素</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (removeEldestEntry(eldest)) {//这个是受保护的方法，需要自己制定删除策略，比如size() &gt; 最大容量,可自己实现，默认为false,也就是不开启</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;removeEntryForKey(eldest.key);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;} else {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (size &gt;= threshold)</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;resize(2 * table.length);</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div>
<div>&nbsp;&nbsp; &nbsp;}</div>
<div>自己重写这个方法，指定删除策略：</div>
<div>
<div>&nbsp;protected boolean removeEldestEntry(Map.Entry&lt;K,V&gt; eldest) {</div>
<div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return false;</div>
<div>&nbsp;&nbsp; &nbsp;}</div>
<div>因此，可用linkedhashmap 构建一个基于LRU算法的缓存。</div>
<div><br />
</div>
<div><br />
</div>
<div>
<div>package com.google.study.cache;</div>
<div><br />
</div>
<div>import java.util.LinkedHashMap;</div>
<div>import java.util.concurrent.locks.ReentrantLock;</div>
<div><br />
</div>
<div>public class SimpleCache&lt;K, V&gt; extends LinkedHashMap&lt;K, V&gt; {</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>private int maxCapacity;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>private ReentrantLock lock = new ReentrantLock();</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public SimpleCache(int maxCapacity, float load_factory) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>super(maxCapacity, load_factory, true);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>this.maxCapacity = maxCapacity;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public int getMaxCapacity() {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return maxCapacity;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public void setMaxCapacity(int maxCapacity) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>this.maxCapacity = maxCapacity;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>@Override</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>protected boolean removeEldestEntry(java.util.Map.Entry&lt;K, V&gt; eldest) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>// TODO Auto-generated method stub</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>return super.removeEldestEntry(eldest);</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public V get(Object key) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>lock.lock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>try {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>return super.get(key);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>} finally {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>lock.unlock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public V put(K k, V v) {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>lock.lock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>try {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>return super.put(k, v);</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>} finally {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>lock.unlock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>@Override</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public void clear() {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>lock.lock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>try {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>super.clear();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>} finally {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>lock.unlock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>@Override</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>public int size() {</div>
<div><br />
</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>lock.lock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>try {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>return super.size();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>} finally {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>lock.unlock();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><br />
</div>
<div>}</div>
</div>
<div><br />
</div>
</div>
</div>
<div><br />
</div>
<div><br />
</div>
<img src ="http://www.blogjava.net/yuyee/aggbug/337579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yuyee/" target="_blank">羔羊</a> 2010-11-08 23:14 <a href="http://www.blogjava.net/yuyee/archive/2010/11/08/337579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>缓存的基本特性</title><link>http://www.blogjava.net/yuyee/archive/2010/11/02/336820.html</link><dc:creator>羔羊</dc:creator><author>羔羊</author><pubDate>Tue, 02 Nov 2010 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/yuyee/archive/2010/11/02/336820.html</guid><description><![CDATA[缓存基本特性：
<div>1.时间记录，进入Cache的时间</div>
<div>2.timeout过期时间，cache里面数据多久过期</div>
<div>3.eviction policy 清楚策略，最不经常访问的数据，最久没访问到的数据</div>
<div>4.命中率:Cache的数据被选中的比率</div>
<div>5.分级Cache，支持 Region分级，比如ehcache</div>
<div>6.分布式，分布在不同的计算机上</div>
<div>7.锁，事务，数据同步</div>
<div><br />
</div>
<div>各个Cluster之间的Cache同步有多种实现方法。比如JMS,RMI&nbsp;</div>
<div>Cache中一般有get,put,remove,clear</div>
<div>对于Cluster的Cache来说，读(get)肯定是local的，只需要从本地内存中获取，而Remove/clear，需要和其他计算机同步，put可以是local的，因为如果读不到，可以从数据库中读</div>
<div>remote put:一台计算机把数据放到自己的Cache中，这个数据需要传播到Cluster其他计算机上，这样其他Cluster可以同步，但是如果数据大，传播的代价就大了</div>
<div>local put:只放到本地计算机的Cache里，不需要同步到其他Cluster，从Cache得不到的数据可以在数据库里读取</div>
<div><br />
</div>
<div><br />
</div>
<div>过期数据：在hibernate等orm工具中，有一个原则，就是不要把没有commit的数据放到缓存中，防止脏读，而且remove之后必须通知其他<span style="font-family: Tahoma; font-size: 12px; line-height: 18px; ">Cluster,保证大部分时间内，给用户的数据不是过期的数据</span></div>
<div><font face="Tahoma" size="3"><span style="font-size: 12px; line-height: 18px;">ORM Cache中，一般分2种Cache,一种是类缓存，一种是查询缓存，类缓存是以ID对应Entity对象，而查询缓存是用来存放一条查询语句对应的结果集，然后再到类缓存里找响应的实体。</span></font></div>
<div><font face="Tahoma" size="3"><span style="font-size: 12px; line-height: 18px;">类缓存：一类Entity一个Region</span></font></div>
<div><font face="Tahoma" size="3"><span style="font-size: 12px; line-height: 18px;">查询缓存:</span></font><span style="font-size:16.0pt;font-family:Calibri;
mso-ascii-font-family:Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:
+mn-cs;color:black;mso-color-index:1;mso-font-kerning:12.0pt;language:en-US">hibernate</span><span style="font-size:16.0pt;font-family:宋体;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:zh-CN">在一个地方维护每个表的最后更新时间，其实也就是放在上面</span><span style="font-size:16.0pt;font-family:Calibri;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:en-US">org.hibernate.cache</span><span style="font-size:16.0pt;font-family:Calibri;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:en-US">. </span><span style="font-size:16.0pt;
font-family:Calibri;mso-ascii-font-family:Calibri;mso-fareast-font-family:宋体;
mso-bidi-font-family:+mn-cs;color:black;mso-color-index:1;mso-font-kerning:
12.0pt;language:en-US">UpdateTimestampsCache</span><span style="font-size:16.0pt;
font-family:宋体;mso-ascii-font-family:Calibri;mso-fareast-font-family:宋体;
mso-bidi-font-family:+mn-cs;color:black;mso-color-index:1;mso-font-kerning:
12.0pt;language:zh-CN">所指定的缓存配置里面，</span><span style="font-size:16.0pt;font-family:宋体;mso-ascii-font-family:
Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;
mso-color-index:1;mso-font-kerning:12.0pt;language:zh-CN">当通过</span><span style="font-size:16.0pt;font-family:Calibri;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:en-US">hibernate</span><span style="font-size:16.0pt;font-family:宋体;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:zh-CN">更新的时候，</span><span style="font-size:
16.0pt;font-family:Calibri;mso-ascii-font-family:Calibri;mso-fareast-font-family:
宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:1;mso-font-kerning:
12.0pt;language:en-US">hibernate</span><span style="font-size:16.0pt;
font-family:宋体;mso-ascii-font-family:Calibri;mso-fareast-font-family:宋体;
mso-bidi-font-family:+mn-cs;color:black;mso-color-index:1;mso-font-kerning:
12.0pt;language:zh-CN">会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表，当</span><span style="font-size:16.0pt;font-family:Calibri;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:en-US">hibernate</span><span style="font-size:16.0pt;font-family:宋体;mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;mso-bidi-font-family:+mn-cs;color:black;mso-color-index:
1;mso-font-kerning:12.0pt;language:zh-CN">查询一个缓存是否存在的时候，如果缓存存在，它还要取出缓存的生成时间和这个缓存所查询的表，然后去查找这些表的最后更新时间，如果有一个表在生成时间后更新过了，那么这个缓存是无效的。&nbsp;</span><span style="font-family: 宋体; font-size: 21px; ">可以看出，只要更新过一个表，那么凡是涉及到这个表的查询缓存就失效了，因此查询缓存的命中率可能会比较低。</span></div>
<div><br />
</div>
<div>7</div>
<img src ="http://www.blogjava.net/yuyee/aggbug/336820.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yuyee/" target="_blank">羔羊</a> 2010-11-02 16:30 <a href="http://www.blogjava.net/yuyee/archive/2010/11/02/336820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>