AspectJ保持异步方法调用的上下文

时间:2016-01-05 18:59:30

标签: java concurrency aop aspectj

我是AspectJ的新手,我想弄清楚,如何保持/跟踪多个异步方法调用的上下文。想象一下以下代码:

@TimerStart
public void doSomething() throws InterruptedException {
    Thread.sleep(1000);
    MyCallable callable = new MyCallable();
    Future future = executorService.submit(callable );
}

private class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        someOtherMethod();
        return null;
    }

    @TimerEnd
    private void someOtherMethod() throws InterruptedException {
        Thread.sleep(1000);
    }
}

我想衡量@TimerStart和@TimerEnd之间的时间。我现在正在努力解决两个问题:

  • 如何在方面之间保留对象。一个方面的字段似乎都是静态的,那么并发问题呢??
  • 如何获得两个建议,一个在@TimerStart之前执行,另一个在@TimerEnd之后执行。

目前我有类似的内容:

public aspect TimerAspect {

    pointcut timerStart(Object object, TimerStart timed):
        execution(@TimerStart * *(..)) && this(object) && @annotation(timed);

    pointcut timerStop(Object object, TimerEnd timed):
        cflow(execution(@TimerEnd * *(..)) && this(object) && @annotation(timed) && !within(FlowTimerAspect));


    before(Object object, TimerStart timed): timerStart(object, timed)  {
        System.out.println("##### Flow timer START");
    }

    after(Object object, TimerEnd timed): timerStop(object, timed)  {
        System.out.println("##### Flow timer STOP");
    }

然而,我现在唯一得到的是StackOverflowException(是的,我知道 - 这就是我在这里问的原因)。

编辑: 我偶然发现了percflow,这似乎只是当@TimerStart和@TimerEnd出现在同一个线程中时才会发挥作用。建议非常感谢!!

public aspect TimerAspect percflow(timerStart(Object, TimerStart)) {

    private long context;

    pointcut timerStart(Object object, TimerStart timed):
            execution(@TimerStart * *(..)) && this(object) && @annotation(timed);

    pointcut timerStop(Object object, TimerEnd timed):
            execution(@TimerEnd * *(..)) && this(object) && @annotation(timed);


    before(Object object, TimerStart timed): timerStart(object, timed)  {
        context = System.currentTimeMillis();
    }

    after(Object object, TimerEnd timed): timerStop(object, timed)  {
        long passed = System.currentTimeMillis() - context;
        System.out.println("passed time: " + passed);
    }
}

1 个答案:

答案 0 :(得分:2)

由于您计划在测量时切换线程,$ frama-c -pp-annot -wp -wp-rte -wp-timeout 100 search.c [kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing) [kernel] Parsing search.c (with preprocessing) /tmp/ppannot97a491.c:1:0: warning: "__STDC_VERSION__" redefined #define __STDC_VERSION__ 201112L ^ <built-in>: note: this is the location of the previous definition /tmp/ppannot97a491.c:2:0: warning: "__STDC_UTF_16__" redefined #define __STDC_UTF_16__ 1 ^ <built-in>: note: this is the location of the previous definition /tmp/ppannot97a491.c:3:0: warning: "__STDC_UTF_32__" redefined #define __STDC_UTF_32__ 1 ^ <built-in>: note: this is the location of the previous definition [wp] Running WP plugin... [wp] Collecting axiomatic usage [rte] annotating function main [rte] annotating function search [wp] 20 goals scheduled [wp] [Qed] Goal typed_main_call_search_pre : Valid [wp] [Qed] Goal typed_main_call_search_pre_2 : Valid [wp] [Alt-Ergo] Goal typed_search_complete_found_nfound : Valid (10ms) (19) [wp] [Alt-Ergo] Goal typed_search_loop_inv_preserved : Valid (17ms) (21) [wp] [Alt-Ergo] Goal typed_search_disjoint_found_nfound : Valid (13ms) (19) [wp] [Qed] Goal typed_search_loop_inv_established : Valid [wp] [Qed] Goal typed_search_loop_inv_2_established : Valid [wp] [Alt-Ergo] Goal typed_main_call_search_pre_3 : Valid (383ms) (93) [wp] [Alt-Ergo] Goal typed_search_loop_inv_2_preserved : Valid (17ms) (33) [wp] [Qed] Goal typed_search_loop_assign : Valid [wp] [Alt-Ergo] Goal typed_search_assert_rte_mem_access : Valid (50ms) (89) [wp] [Alt-Ergo] Goal typed_search_assert_rte_unsigned_overflow : Valid (13ms) (30) [wp] [Qed] Goal typed_search_assign_part1 : Valid [wp] [Qed] Goal typed_search_assign_part2 : Valid [wp] [Qed] Goal typed_search_assign_part3 : Valid [wp] [Qed] Goal typed_search_assign_part4 : Valid [wp] [Qed] Goal typed_search_loop_term_decrease : Valid (3ms) [wp] [Qed] Goal typed_search_loop_term_positive : Valid [wp] [Alt-Ergo] Goal typed_search_nfound_post : Valid (17ms) (33) [wp] [Alt-Ergo] Goal typed_search_found_post : Unknown (54.3s) [wp] Proved goals: 19 / 20 Qed: 11 (3ms-3ms) Alt-Ergo: 8 (10ms-383ms) (93) (unknown: 1) 实例化方法不会对您有所帮助。您必须坚持使用默认的单例方面,并将感兴趣对象的计时值保存在percflow中。这样,只要与时间相关联的对象/线程处于活动状态,就可以保持时间。 我们需要另一个注释来标记将新对象(在此示例中为WeakHashMap)与您的时间相关联的事件。我们称之为Callable@TimerJoin注释类似于您现有的@TimerJoin@TimerStart注释。您的测量方面将如下所示。

@TimerEnd

简单的import java.util.Map; import java.util.WeakHashMap; public aspect TimerAspect { private final Map<Object, Timer> objectTiming = new WeakHashMap<>(); private final ThreadLocal<Timer> currentThreadTimer = new ThreadLocal<>(); pointcut timerStart(Object object): execution(@TimerStart * *(..)) && this(object); pointcut timerStop(Object object): execution(@TimerEnd * *(..)) && this(object); pointcut timerJoin(Object object): (execution(@TimerJoin * *(..)) || execution(@TimerJoin *.new(..)) ) && this(object); before(Object object): timerStart(object) { Timer timer = new Timer(); timer.start(); objectTiming.put(object, timer); currentThreadTimer.set(timer); System.out.println("##### Flow timer START"); } before(Object object): timerJoin(object) { Timer timing = currentThreadTimer.get(); objectTiming.put(object, timing); System.out.println("##### Flow timer JOIN"); } after(Object object): timerStop(object) { Timer timing = objectTiming.get(object); timing.stop(); System.out.println("##### Flow timer STOP"); System.out.println("Elapsed: " + timing.getElapsed()); } } 类:

Timer.java

修改你的callable以将其标记为加入当前线程上的计时器:

public class Timer {

    private long start;
    private long stop;

    public long getStart() {
        return start;
    }

    public long getStop() {
        return stop;
    }

    public void start() {
        start = System.currentTimeMillis();
    }

    public void stop() {
        stop = System.currentTimeMillis();
    }

    public long getElapsed() {
        return stop-start;
    }
}

其余代码将是相同的。

您可能会注意到方面正在使用private class MyCallable implements Callable { @TimerJoin public MyCallable() { } @Override public Object call() throws Exception { someOtherMethod(); return null; } @TimerEnd private void someOtherMethod() throws InterruptedException { Thread.sleep(1000); } } 作为存储方式,以便当前计时器能够将其与新对象相关联。您可以为此选择另一种存储,但为了示例,我试图保持简单。此外,为了简单起见,我省略了对方面的空值的任何安全检查。你需要自己处理角落案件。