FutureTask在缓存中使用

好久不见. 提交于 2019-11-28 15:22:54

缓存主要作用是提高应用程序吞吐量和响应性,当然也有负面影响,占用更多内存。在设计SqlTemplate也有个简单的本地缓存,sql模板实际只需要解释一次就可以了,以后的调用复用之前解释过。开始的时候是使用简单的HashMap实现的,但是在并发情况下会出现重复解释,下面是第一版的代码片段。

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改进后的第二版本代码,看似很完美^_^。

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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!