最近协助一些bea客户做调优,他们使用了spring,出现了各种各样的性能问题,这些问题其实都是不容易重现的,其中,我自己捕获了一些threaddump,并report了给spring jira。这个case的情况是:spring会偶然出现cpu 100%的情况,weblogic server崩溃,我后来分析了线程dump,觉得是一种lock contention的情形,幸好,很快给我fixed了这个bug:
使用java编程的同学都建议review一下,呵呵:
这是2.5.4以前的代码:
/**
* cache of transactionattributes, keyed by defaultcachekey (method target class).
* as this base class is not marked serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is serializable.
*/
final
map attributecache
=
new
hashmap();
/**
* determine the transaction attribute for this method invocation.
*
defaults to the class's transaction attribute if no method attribute is found.
*
@param
method the method for the current invocation (never null
)
*
@param
targetclass the target class for this invocation (may be null
)
*
@return
transactionattribute for this method, or null
if the method
* is not transactional
*/
public
transactionattribute gettransactionattribute(method method, class targetclass) {
//
first, see if we have a cached value.
object cachekey
=
getcachekey(method, targetclass);
synchronized
(
this
.attributecache) {
object cached
=
this
.attributecache.get(cachekey);
if
(cached
!=
null
) {
//
value will either be canonical value indicating there is no transaction attribute,
//
or an actual transaction attribute.
if
(cached
==
null_transaction_attribute) {
return
null
;
}
else
{
return
(transactionattribute) cached;
}
}
else
{
//
we need to work it out.
transactionattribute txatt
=
computetransactionattribute(method, targetclass);
//
put it in the cache.
if
(txatt
==
null
) {
this
.attributecache.put(cachekey, null_transaction_attribute);
}
else
{
if
(logger.isdebugenabled()) {
logger.debug(
"
adding transactional method [
"
method.getname()
"
] with attribute [
"
txatt
"
]
"
);
}
this
.attributecache.put(cachekey, txatt);
}
return
txatt;
}
}
}
这是2.5.4 fixed后的代码:
/**
* cache of transactionattributes, keyed by defaultcachekey (method target class).
* as this base class is not marked serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is serializable.
*/
final
map attributecache
=
collectionfactory.createconcurrentmapifpossible(
16
);
/**
* determine the transaction attribute for this method invocation.
*
defaults to the class's transaction attribute if no method attribute is found.
*
@param
method the method for the current invocation (never null
)
*
@param
targetclass the target class for this invocation (may be null
)
*
@return
transactionattribute for this method, or null
if the method
* is not transactional
*/
public
transactionattribute gettransactionattribute(method method, class targetclass) {
//
first, see if we have a cached value.
object cachekey
=
getcachekey(method, targetclass);
object cached
=
this
.attributecache.get(cachekey);
if
(cached
!=
null
) {
//
value will either be canonical value indicating there is no transaction attribute,
//
or an actual transaction attribute.
if
(cached
==
null_transaction_attribute) {
return
null
;
}
else
{
return
(transactionattribute) cached;
}
}
else
{
//
we need to work it out.
transactionattribute txatt
=
computetransactionattribute(method, targetclass);
//
put it in the cache.
if
(txatt
==
null
) {
this
.attributecache.put(cachekey, null_transaction_attribute);
}
else
{
if
(logger.isdebugenabled()) {
logger.debug(
"
adding transactional method [
"
method.getname()
"
] with attribute [
"
txatt
"
]
"
);
}
this
.attributecache.put(cachekey, txatt);
}
return
txatt;
}
}
但是2.5.4 snapshot是未经很好测试的版本,客户一般不太敢用。
我不知道其实有多少客户真正地把spring投入到高并发性环境下使用,
如果有,他们应该会能碰到我所碰到的情形。