-1

Here is my code:

   class A{
    @Autowired
    B objB;

   public method1(){
       List<String> ids = new ArrayList<String>();
       ids.add("1");
       ids.add("2");
       ids.add("3");
       List<CompletableFuture<String>> listOfFuture ids.stream()
                        .map(id -> CompletableFuture.supplyAsync(() -> 
                                  objB.method2(id)).collect(toList());
   }
}

    class B{
    @Inject
    D objD;
    @Inject
    E objE

    public String method2(String id){
        String transformedId = objD.method3(id);
        return objE.method4(transformedId);
    }
}

class B has method2 has objects which are not thread safe. I want to make new instances of B so that each thread has its own objects while executing method2. I can use spring's async utility for method2 and call this method asynchronously from A instead of using CompletableFuture in class A. This will make method2 thread safe. How can I make method2 thread safe if I used CompletableFuture? Is my assumption correct that I need different object for Class B every time I spawn a thread to invoke method2 since class B is not thread safe?

suj sekar
  • 1
  • 3
  • 1
    Use constructor injection and make sure that each class A instance has its own injected instance of class B. If you pass the instance of class B into the method, it'll be as thread safe as the object that passes it in. – duffymo May 19 '17 at 19:38
  • Shared, mutable data is the issue. Get rid of all state in class A. Pass the instance of class B as a parameter into method() and you're thread safe. – duffymo May 19 '17 at 19:44
  • Can you please elaborate with code sample? – suj sekar May 19 '17 at 23:19

2 Answers2

0

Here's how I'd recommend you do it:

 class A{


   public method1(B objB){
       List<String> ids = new ArrayList<String>();
       ids.add("1");
       ids.add("2");
       ids.add("3");
       List<CompletableFuture<String>> listOfFuture ids.stream()
                        .map(id -> CompletableFuture.supplyAsync(() -> 
                                  objB.method2(id)).collect(toList());
   }
}

This is thread safe because there's no shared mutable data. The parameters passed into each method are independent.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • This does not solve the problem since all the thread spawned by fork-join pool for CompletableFuture is still going to use same objB. I need a different instance of B every time method2 is invoked. – suj sekar May 20 '17 at 18:58
  • No, it's going to use the reference to the object that you pass to the method each time. Pass a different reference when you call it. – duffymo May 20 '17 at 19:38
0

Another approach by setting scope of a bean as prototype. It is not the best way but we could do this way also

@Component
class A implements ApplicationContextAware {
        ApplicationContext applicationContext;
        public void method1() {
            List<String> ids = new ArrayList<String>();
            ids.add("1");
            ids.add("2");
            ids.add("3");
            List<CompletableFuture<String>> listOfFuture = ids.stream()
                    .map(id -> CompletableFuture.supplyAsync(() -> applicationContext.getBean(B.class).method2(id)))
                    .collect(Collectors.toList());
        }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;

        }
    }

    @Component("beanB")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    class B {
        public String method2(String id) {
            // Your code
        }
    }
Vip
  • 1,448
  • 2
  • 17
  • 20
  • Is my assumption correct that I need different object for Class B every time I spawn a thread to invoke method2 since class B is not thread safe? – suj sekar May 20 '17 at 19:08
  • 1
    If class B is not thread safe then either you have to make it thread safe or create new object for every thread. But I think best practice would be to make class b thread safe by removing shared state if possible. – Vip May 21 '17 at 12:09