欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一次同步不当的bug记录。

程序员文章站 2022-05-31 11:20:01
...
昨天晚上,收到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