FutureTask在緩存中使用

緩存主要做用是提升應用程序吞吐量和響應性,固然也有負面影響,佔用更多內存。在設計SqlTemplate也有個簡單的本地緩存,sql模板實際只須要解釋一次就能夠了,之後的調用複用以前解釋過。開始的時候是使用簡單的HashMap實現的,可是在併發狀況下會出現重複解釋,下面是初版的代碼片斷。 java

public class Configuration {

	private ConcurrentHashMap<String, SqlTemplate > templateCache;
    ......

	public SqlTemplate getTemplate(final String content) {
		if (cacheTemplate) { //是 不然緩存模板

			SqlTemplate sqlTemplate = templateCache.get(content);
			  
	        if (sqlTemplate != null){
	    	   sqlTemplate  = createTemplate(content) ;
	    	   
	    	   templateCache.put(content, sqlTemplate) ;
	        }
	        return sqlTemplate;
		}
		return createTemplate(content);
	}
        //解釋構建模板對象
	private SqlTemplate createTemplate(String content) {
		SqlTemplate template = new SqlTemplate.SqlTemplateBuilder(this, content)
				.build();
		return template;
	}
	......
}

經過看上面的代碼,很容易發現問題的所在,一個線進createTemplate解釋模板,其餘線程不知道這個模板已經在解釋中,因此可能會出現同sql模板會出現屢次計算。理想的狀況下其餘線程知道模板在解釋中,只需等待完成。下面是使用FutureTask改進後的第二版本代碼,看似很完美^_^。 sql

public class Configuration {

	private ConcurrentHashMap<String, FutureTask<SqlTemplate>> templateCache;

......

	public SqlTemplate getTemplate(final String content) {

		if (cacheTemplate) {////是 不然緩存模板

			FutureTask<SqlTemplate> f = templateCache.get(content);

			if (f == null) {
				FutureTask<SqlTemplate> ft = new FutureTask<SqlTemplate>(
						new Callable<SqlTemplate>() {

							public SqlTemplate call() throws Exception {
								return createTemplate(content);
							}
						});

				f = templateCache.putIfAbsent(content, ft);

				if (f == null) {
					ft.run();
					f = ft;
				}
			}

			try {
				return f.get();
			} catch (Exception e) {
				templateCache.remove(content); //防止緩存污染
				throw new RuntimeException(e);
			}

		}

		return createTemplate(content);

	}

    //解釋構建模板對象
	private SqlTemplate createTemplate(String content) {
		SqlTemplate template = new SqlTemplate.SqlTemplateBuilder(this, content)
				.build();
		return template;
	}

......
}


第二版解決了初版的缺陷(重複解釋),併發性也不錯,能很好返回已經解釋過的結果。此次緩存不是結果值,而是一個FutureTask,關於Future詳細使用請參考啊了個裏寫的《Java 併發之 Future 接口。關於SqlTemplate請參考http://my.oschina.net/u/866190/blog/175800 緩存

相關文章
相關標籤/搜索