一次同步不当的bug记录。

阅读更多
昨天晚上,收到QA报告,说页面里面一大堆数据无法显示。
别急,别急,先保护现场,用另外一台服务器在调试模式下继续测试,想办法复现这个问题。

到了晚上,问题终于又出现了。打开远程调试,检查一下运行线程,发现有一大堆用于抓取外部数据的Servlet线程不动了。
原来,一条记录指向了一个公司内部ip地址,员工下班关机之后,无法获取该记录,导致装载延迟。
而我们的开发人员在这里为了避免同一资源的多次解析,用了一个全局的同步锁,一下子其他数据也无法装载。

问题代码:
    Object data = getFromCache...;
    if (data != null) {
      return data;
    }
    synchronized (LOCK) {
        Object data =getFromCache...;
        if (data != null) {
           return data;
        }
        data = buildData..
        saveToCache...
        return data
    }


上面的代码看似还行,可是,确保了我们不会重复解析同一数据,但是,加锁加的不合适,一旦任何一个资源延迟,都将导致全部线程暂停。

给一下修改后的形式:
	private Map lockMap = new HashMap();
.....
	protected String getCachedResource(String url) throws Exception {
		String key =  url;
		Object data = getFromCache(key);
		if (data == null) {
			//获取资源对应的锁
			Object lock = requireLock(url);
			synchronized (lock) {
				data = parser.parse(url);
				saveToCache(key, data);
			}
			//删除锁
			lockMap.remove(key);
		}
		return (String) data;
	}

	private Object requireLock(Object key) {
		synchronized (lockMap) {
			Object lock = lockMap.get(key);
			if (lock == null) {
				lock = new Object();
				lockMap.put(key, lock);
			}
			return lock;
		}
	}

仍外抱怨一下繁琐的代码风格
一个内部类,构造函数最多带n个参数,能后呢,某些人为了可能的使用方便,居然给配上了2的n次方个构造函数。晕啊,我真不想看你这么多的文档:(

你可能感兴趣的:(Servlet)