Home > Software engineering >  Run some code before every CompletableFuture.runAsync()
Run some code before every CompletableFuture.runAsync()

Time:09-15

I have an application with a couple runAsync(). These runAsync() call a variety of other methods, and I'd like to run some code before each of them but within the same thread.

So for example I have main thread, then I call runAsync(MyClass::myMethod), Thread1 is created and before myMethod() gets called, within the same thread (Thread1), another method is called.

I assume this would involve some kind of wrapper of some sorts but since this uses lambda expressions and async threads I'm a bit lost on how that'd be done.

Thanks in advance

Edit: I'd like to clarify that methodToRunBeforeAsync() should be hidden from other devs. Something like using a wrapper so you don't have to worry to make the calls to methodToRunBeforeAsync()

CodePudding user response:

In order to run code around those lambdas there are a couple of options. One would be AOP but that can be complex to set up so if you're able to change the calls, you could do the following:

Option 1: Create a WrapperRunnable

Just create a wrapper/decorator that executes whatever additional code you need. You can use that approach wherever a Runnable is required.

class WrapperRunnable implements Runnable {
   Runnable delegate;

   WrapperRunnable(Runnable r) {
     delegate= r;
   }

   public void run() {
     //any code before
     delegate.run();
     //any code after
   }
}

Usage: CompletableFuture.runAsync(new WrapperRunnable(MyClass::myMethod))

Option 2: wrap runAsync()

Provide your own runAsync(Runnable) method that internally creates a decorator lambda or uses the decorator defined in option 1. That calls CompletableFuture.runAsync() internally and can only be used as a replacement for this method.

class MyCompletables {
   public static CompletableFuture<Void> runAsync(Runnable runnable) {
    return CompletableFuture.runAsync(() -> {
        //any code before
        runnable.run();
        //any code after
      });
   }
}

Using the decorator of option 1:

class MyCompletables {
   public static CompletableFuture<Void> runAsync(Runnable runnable) {
     return CompletableFuture.runAsync(new WrapperRunnable(runnable));
   }
}

Usage: MyCompletables.runAsync(MyClass::myMethod)

Note that there are other options as well, some being more flexible, some more elegant, but this should get you started while still being easy to understand.

CodePudding user response:

Something like this? Just wrap the task and make sure people use myRunAsync instead of the standard one. Give it a better name, obviously.

public static void main(String[] args) {
    myRunAsync(() -> System.out.println("Task")).join();
}

private static CompletableFuture<Void> myRunAsync(Runnable runnable) {
    return CompletableFuture.runAsync(() -> {
        preTask();
        runnable.run();
    });
}

private static void preTask() {
    System.out.println("Pre");
}

CodePudding user response:

One simple example would be:

runAsync(() -> {
            myOtherObject.myMethodToRunBefore();
            myObject.myMethod();
         }
)

You can either add the call to myMethodToRunBefore() in the first line of the body myMethod() or create wrapper object.The choice depends if the myMethod should be separated from the call to myMethodToRunBefore (then use wrapper) or they always need to be called together in same order (then add the call to the beforeMethod in the first line of myMethod).

  • Related