【发布时间】:2011-05-26 22:38:23
【问题描述】:
我的测试表明以下代码不是线程安全的,即使该类是无状态的并且方法之间共享的所有状态都作为参数从方法传递到方法。多个线程正在调用以下类的单个实例。
public class ThingFinder {
Token findFoo(TokenIterator<? extends Token> iterator,
Token start, final Token limit) {
Token partOfFoo = searchForward(iterator, start, new TokenSearcher() {
int maxTokens = 5;
@Override
public SearchAction assessToken(Token aToken) {
if (limit != null && (aToken.getStart() >= limit.getStart())) {
return SearchAction.STOP;
}
if (maxTokens-- == 0) {
return SearchAction.STOP;
}
if (isAThing(aToken)) {
return SearchAction.MATCH;
} else {
return SearchAction.IGNORE;
}
}
});
return partOfFoo;
}
public Token extractAThing(TokenIterator<? extends Token> iterator) {
Token start = findStart(iterator);
Token limit = findLimit(iterator, start);
return findFoo(iterator, start, limit);
}
}
这个类的意图是线程安全的,因为它是无状态的,所有需要在方法之间共享的状态都作为参数从一个方法传递到另一个方法。然而,测试表明有时我们会在这一行得到一个空指针异常:
if (limit != null && (aToken.getStart() >= limit.getStart())) {
似乎在检查空值和调用 getStart 之间的某个时间,参数限制变为空。
请注意,findFoo 方法将 limit 参数声明为 final:
Token findFoo(TokenIterator<? extends Token> iterator, Token start,
final Token limit) {
是否最终方法参数不在堆栈帧上,而是在方法的所有调用之间共享一个实例?如果所有调用之间共享一个实例是真的,那么这是否意味着使用最终参数会使一个类天生线程不安全?
【问题讨论】:
-
您确定限制为空吗?如果 aToken 为空,你会得到同样的异常。
-
你有多确定
limit是罪魁祸首,而不是aToken? -
aToken 保证不为空。从执行回调的框架中可以清楚地看出,但很难在帖子中显示。此外,我在测试期间添加了对 aToken 的空指针检查。
-
getStart() 的返回类型是什么?是原始的吗?
-
Token 是不可变的类吗?如果不是,并且您在线程之间共享 Token 实例,这将不是线程安全的
标签: java multithreading thread-safety anonymous-function