velocity1.6.1 并发问题

vevocity在做渲染时会调用 org.apache.velocity.util.introspection.ClassMap$MethodCache.get方法 该方法完整代码(velocity1.6.1版本)如下

private final Map cache = new HashMap();

public Method get(final String name, final Object [] params)

throws MethodMap.AmbiguousException

{

String methodKey = makeMethodKey(name, params);

Object cacheEntry = cache.get(methodKey);

if (cacheEntry == CACHE_MISS)

{

// We looked this up before and failed.

return null;

}

if (cacheEntry == null)

{

try

{

// That one is expensive...

cacheEntry = methodMap.find(name, params);

}

catch(MethodMap.AmbiguousException ae)

{

/*

* that's a miss :-)

*/

cache.put(methodKey, CACHE_MISS);

throw ae;

}

cache.put(methodKey,

(cacheEntry != null) ? cacheEntry : CACHE_MISS);

}

// Yes, this might just be null.

return (Method) cacheEntry;

}


这里需要注意的是cache部分的实现:cache = new HashMap();由于HashMap不是线程安全的,这样在并发较高的情况下会导致线程安全的问题.使用中发现,在高并发的情况下,服务器的CPU可能会暴涨,在10%左右,java进程的cpu在400%左右,而且一直下不去,即使没有访问.通过分析java线程,发现在HashMap.get方法会堵死,get里面的while循环会新数据的加入变得不可预料.jstack片段:

"TP-Processor28" daemon prio=10 tid=0x00002aab4db7e000 nid=0x2a29 runnable [0x0000000042e37000]

java.lang.Thread.State: RUNNABLE

at java.util.HashMap.get(HashMap.java:303)

at org.apache.velocity.util.introspection.ClassMap$MethodCache.get(ClassMap.java:259)

at org.apache.velocity.util.introspection.ClassMap.findMethod(ClassMap.java:102)

at org.apache.velocity.util.introspection.IntrospectorBase.getMethod(IntrospectorBase.java:105)

at org.apache.velocity.util.introspection.Introspector.getMethod(Introspector.java:94)

at org.apache.velocity.runtime.parser.node.PropertyExecutor.discover(PropertyExecutor.java:118)

at org.apache.velocity.runtime.parser.node.PropertyExecutor.<init>(PropertyExecutor.java:56)

at org.apache.velocity.util.introspection.UberspectImpl.getPropertyGet(UberspectImpl.java:246)

at org.apache.velocity.runtime.parser.node.ASTIdentifier.execute(ASTIdentifier.java:148)

at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:252)

at org.apache.velocity.runtime.parser.node.ASTReference.render(ASTReference.java:332)

at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:336)

at org.apache.velocity.Template.merge(Template.java:328)


这种堵塞容易发生在多CPU高并发的机器上,HashMap的桶在存了大量的数据后get操作的for循环取对象的操作在同时有读有写的情况下变得不可预知。在使用循环时,一定注意退出条件,当有极端境况发生循环无法退出时就悲剧了。

velocity1.6.4版本对该部分的cache已经做了处理,使用了线程安全的cache:

 cache = MapFactory.create(false);
 MapFactory对并发map进行了处理,具体代码可见 org.apache.velocity.util.MapFactory类

建议大家使用1.6.4以上版本的velocity,同时在使用hashMap的时候一定要注意线程安全的问题.

posted @ 2011-03-29 14:58  redcreen  阅读(2301)  评论(0编辑  收藏  举报