我编写了简单的线程安全组件,用于测量多线程应用程序的性能,类似于Java配置文件工具。这个想法是n层节点树,每个节点是分析应用程序调用的方法的统计数据,并且位于执行树相应的级别和相应父级下。统计信息有几个计数器,其中之一是调用次数,调用方法时,调用次数会随着每次执行而增加。目前我不太关心胎面安全,因此计数器只有简单的长类型和由运算符++ 完成的增量。下面我放置一个代码示例。 现在的问题是:应用程序工作几个小时后,一些计数器变为负值。即使某些踏板同时增加相同的计数器,你知道会发生什么吗? 它发生在RAD环境中IBM的Java 7下。我在 Oracle 的 Java 8 下运行了类似的应用程序,但没有发生。
class Node<T>{
Node parent;
Map<T, Node> children = new ConcurrentHashMap<T, Node>();
Stats stats = new Stats();
Node(Node parent) { this.parent = parent; }
void checkIn(){ stats.checkIn(); }
void checkout(){ stats.checkout(); }
}
class Stats{
long start, time, calls;
void checkIn(){ ... calls++;}
void checkout(){ ... }
}
class ExecutionTree<T>{
static Map<Long, ExecutionTree> inst = new ConcurrentHashMap<Long, ExecutionTree>();
Node<T> currentNode;
static ExecutionTreeProfiler getInstance(){
return inst.get(Tread.currentTread().getId());
}
void checkIn(T key){
// actual code is more thread-safe, but I wrote here for simplyfy it as not relevant to question
Node<T> child =
currentNode.children.contains(key)?
currentNode.children.get(key) :new Node<T>(current node);
currentNode.children.put(key, child);
child.checkin();
currentNode = child;
}
void checkout(T key) {
current node.checkout();
currentNode = currentNode.parent;
}
≠======== measuring application ========
...
void someMethod1(){
ExecutionTree.getInstance().checkIn("method1");
.....
ExecutionTree.getInstance().checkOut();
}
…someMethod2() ...
最佳答案
遗憾的是,在执行多线程程序时,您必须关心线程安全。使用++ 操作递增 long 不是原子操作,也不是线程安全的...请使用 Ted Hopp 在评论中建议的 AtomicLong
和 incrementAndGet()
。 ..
关于Java多线程自增可以为负数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40927184/