我编写简单的线程安全组件,它测量多线程应用程序的性能,类似于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() ...
答案 0 :(得分:1)
可悲的是,在执行多线程程序时, 要关心线程安全性。使用++操作递增long不是原子操作也不是线程安全的...转到Ted Hopp在评论中建议的AtomicLong
和incrementAndGet()
...