一个简单的(未经测试,使用风险自负)可能有效的解决方案是为每个线程维护每个方法的计数器:
private static final ConcurrentHashMap>
COUNTERS = new ConcurrentHashMap<>();
public static int getInvocationId(String methodName, long threadId) {
return counter(methodName, threadId).getAndIncrement();
}
private static AtomicInteger counter(String methodName, long threadId) {
ConcurrentHashMap map = countersForMethodName(methodName);
AtomicInteger counter = map.get(threadId);
if (counter == null) {
AtomicInteger newCounter = new AtomicInteger();
counter = map.putIfAbsent(threadId, newCounter);
if (counter == null) {
return newCounter;
}
}
return counter;
}
private static ConcurrentHashMap countersForMethodName(
String methodName) {
ConcurrentHashMap map = COUNTERS.get(methodName);
if (map == null) {
ConcurrentHashMap newMap = new ConcurrentHashMap<>();
map = COUNTERS.putIfAbsent(methodName, newMap);
if (map == null) {
return newMap;
}
}
return map;
}
然后,在你的建议中,例如:
int invocationId = getInvocationId(thisJoinPoint.getSignature().getName(),
Thread.currentThread().getId());
// do what you want with invocationId
请注意,这依赖于在与目标方法相同的线程中执行的建议 – 遗憾的是,我对AspectJ不太熟悉,不知道这个假设是否总是成立.
CAVEAT:如果您的环境始终创建并过期新线程,那么上面的树将继续增长(实质上是内存泄漏).如果这是一个问题,那么你需要输入一些其他代码来定期枚举所有活动线程,并从树中删除过期的条目.在这种情况下,您可能希望使用映射每线程ID,然后使用每个方法名称来提高修剪效率.