Как создать уникальный хэш-код для экземпляра метода? - PullRequest
4 голосов
/ 12 августа 2011

Я выполняю некоторое профилирование с Aspectj.

Мне нужно однозначно определить экземпляры метода, к которому было получено доступ к полю. Например:

public class Class{ int a; int b;
public void method1(){

  setA(5);
  setB(6); 

В этом случае с AspectJ Iможет получить, что доступ к a и доступ к b были сделаны методами setA и SetB.А с

Thread.currentThread().getStackTrace();

я могу знать, что setA и setB были вызваны методом method1 ().

Недостаточно имени метода, мне также нужно однозначно идентифицировать экземплярmethod.

Например, если method1 вызывается много раз, я должен различить, что доступ к a и доступ к b были сделаны различными экземплярами метода 1.

Любое предложение, как можно получитьэкземпляр хеш-кода метода excution?

1 Ответ

1 голос
/ 15 августа 2011

Простое (непроверенное, использование на свой страх и риск) решение, которое могло бы сработать, состояло бы в том, чтобы поддерживать счетчик для метода на поток:

private static final ConcurrentHashMap<String, ConcurrentHashMap<Long, AtomicInteger>>
    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<Long, AtomicInteger> 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<Long, AtomicInteger> countersForMethodName(
    String methodName) {
    ConcurrentHashMap<Long, AtomicInteger> map = COUNTERS.get(methodName);
    if (map == null) {
        ConcurrentHashMap<Long, AtomicInteger> 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: Если ваша среда все время создает и истекает новые потоки, то вышеупомянутое дерево будет продолжать расти (по сути, утечка памяти). Если это проблема, то вам нужно будет вставить какой-то другой код, чтобы периодически перечислять все активные потоки и удалять устаревшие записи из дерева. В этом случае вы можете использовать идентификатор карты для каждого потока, а затем имя для метода, чтобы сделать сокращение более эффективным.

...