Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Hook Thread Creations

I did not answer right away because I was busy, sorry. I think that the answer is a little bit more complex because maybe you do not know exactly how your 3rd party application or library handles concurrency. Maybe it directly creates threads, maybe it uses thread pools. Then possibly you rather want to intercept when threads are started than when they are created. Maybe the library uses an ExecutorService or - even worse - a ScheduledExecutorService. Unless you really weave into execution joinpoints within the JDK there is no way to capture 100% of all the thread/task creation/starting events. What makes things worse is that it is kinda hard to hook into Runnable creation because mostly anonymous subclasses or even lambdas (like in my example) are used. Please use the DEBUG switch in my sample aspect in order to see in more detail what is going on.

 
Let us assume your third party code is like this:
 
package org.thirdparty;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Application {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        new Thread(() -> System.out.println("Thread")).start();

        Runnable r1 = () -> System.out.println("Runnable 1");
        Runnable r2 = () -> System.out.println("Runnable 2");
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(r1);
        executor.execute(r2);
        Thread.sleep(500);
        executor.execute(r1);
        executor.execute(r2);
        Thread.sleep(500);

        Callable<Integer> task = () -> { System.out.println("Callable task"); return 11; };
        executor.submit(task);

        List<Callable<Integer>> tasks = new ArrayList<>();
        tasks.add(task);
        tasks.add(task);
        executor.invokeAll(tasks);
        executor.invokeAny(tasks);
        executor.shutdown();

        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> System.out.println("Scheduled task"), 0, 250, TimeUnit.MILLISECONDS);
        Thread.sleep(1000);
        scheduler.shutdown();
    }
}

As you can see, several types of concurrency tools are used here. Now here is an aspect trying to capture what is going on:

package de.scrum_master.aspect;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;

public aspect ThreadInterceptor {
    private static boolean DEBUG = false;
    before() :
        if(!DEBUG) && (
            call(* Thread+.start()) ||
            call(* ExecutorService+.execute(..)) ||
            call(* ExecutorService+.submit(..)) ||
            call(* ExecutorService+.invokeAll(..)) ||
            call(* ExecutorService+.invokeAny(..)) ||
            call(* ScheduledExecutorService.scheduleAtFixedRate(..))
        )
    {
        System.out.println(thisJoinPoint);
    }

    before() :
        if(DEBUG) &&
        within(*) &&
        !within(ThreadInterceptor) &&
        !get(* *) &&
        !call(* println(..))
    {
        System.out.println(thisJoinPoint);
    }
}

The first pointcut/advice shows where you need to hook into in order to capture the most obvious events. Try the second one to see more. The output for the first one looks like this:

call(void java.lang.Thread.start())
Thread
call(void java.util.concurrent.ExecutorService.execute(Runnable))
call(void java.util.concurrent.ExecutorService.execute(Runnable))
Runnable 1
Runnable 2
call(void java.util.concurrent.ExecutorService.execute(Runnable))
call(void java.util.concurrent.ExecutorService.execute(Runnable))
Runnable 1
Runnable 2
call(Future java.util.concurrent.ExecutorService.submit(Callable))
call(List java.util.concurrent.ExecutorService.invokeAll(Collection))
Callable task
Callable task
Callable task
call(Object java.util.concurrent.ExecutorService.invokeAny(Collection))
Callable task
Callable task
call(ScheduledFuture java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate(Runnable, long, long, TimeUnit))
Scheduled task
Scheduled task
Scheduled task
Scheduled task

Please note how the aspect is unable to capture each single scheduled task execution but only captured the scheduling start event instead.

Feel free to experiment and come up with a better solution. I was just curious and playing around.

--
Alexander Kriegisch
https://scrum-master.de

 

Andy Clement schrieb am 23.07.2016 01:45:

 
aspect X {
  before(): call(Thread.new(..)) { // Thread constructor called
    System.out.println("Thread created!");
  }
  before(): call(* Thread.start(..)) { // Thread.start called
    System.out.println("Thread started!");
  }
}
 
Andy
 
On Jul 20, 2016, at 1:07 AM, ants <anto.aravinth.cse@xxxxxxxxx> wrote:
 
 
 
On Wed, Jul 20, 2016 at 1:03 PM, Alexander Kriegisch-2 [via AspectJ] <[hidden email]> wrote:
You can easily hook into places where your own code creates threads.

If you need to hook into threads created by third party libs, you need to weave their binaries via post-compile or load-time weaving.
 
Can you give some examples for it with respect to weaving thread creation? 
 


Theoretically you can also weave into the JDK, creating your own tools.jar with woven classes, but probably you do not want to go that far. I have done that in the past just for the fun of it.
--
Alexander Kriegisch
https://scrum-master.de
 

> Am 20.07.2016 um 05:42 schrieb ants <[hidden email]>:
>
> Hi All,
>
> Is there a way to hook to thread creations and destroy from AspectJ
> pointcuts?
>
> ` Anto.
>
>
>
> --
> View this message in context: http://aspectj.2085585.n4.nabble.com/Hook-Thread-Creations-tp4652108.html
> Sent from the AspectJ - users mailing list archive at Nabble.com.
> _______________________________________________
> aspectj-users mailing list
> [hidden email]
> To change your delivery options, retrieve your password, or unsubscribe from this list, visit
> https://dev.eclipse.org/mailman/listinfo/aspectj-users

_______________________________________________
aspectj-users mailing list
[hidden email]
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users

smime.p7s (3K) Download Attachment
 
If you reply to this email, your message will be added to the discussion below:
http://aspectj.2085585.n4.nabble.com/Hook-Thread-Creations-tp4652108p4652109.html
To unsubscribe from Hook Thread Creations, click here.
NAML
 
View this message in context: Re: Hook Thread Creations
Sent from the AspectJ - users mailing list archive at Nabble.com.
_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users
package org.thirdparty;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Application {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        new Thread(() -> System.out.println("Thread")).start();

        Runnable r1 = () -> System.out.println("Runnable 1");
        Runnable r2 = () -> System.out.println("Runnable 2");
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(r1);
        executor.execute(r2);
        Thread.sleep(500);
        executor.execute(r1);
        executor.execute(r2);
        Thread.sleep(500);

        Callable<Integer> task = () -> { System.out.println("Callable task"); return 11; };
        executor.submit(task);

        List<Callable<Integer>> tasks = new ArrayList<>();
        tasks.add(task);
        tasks.add(task);
        executor.invokeAll(tasks);
        executor.invokeAny(tasks);
        executor.shutdown();

        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> System.out.println("Scheduled task"), 0, 250, TimeUnit.MILLISECONDS);
        Thread.sleep(1000);
        scheduler.shutdown();
    }
}
package de.scrum_master.aspect;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;

public aspect ThreadInterceptor {
    private static boolean DEBUG = false;
    before() :
        if(!DEBUG) && (
            call(* Thread+.start()) ||
            call(* ExecutorService+.execute(..)) ||
            call(* ExecutorService+.submit(..)) ||
            call(* ExecutorService+.invokeAll(..)) ||
            call(* ExecutorService+.invokeAny(..)) ||
            call(* ScheduledExecutorService.scheduleAtFixedRate(..))
        )
    {
        System.out.println(thisJoinPoint);
    }

    before() :
        if(DEBUG) &&
        within(*) &&
        !within(ThreadInterceptor) &&
        !get(* *) &&
        !call(* println(..))
    {
        System.out.println(thisJoinPoint);
    }
}

Back to the top