2017-05-19 6 views
-1

에 대한 클래스의 새로운 인스턴스를 생성하는 것은 내 코드입니다 :방법 (CompletableFuture를 사용하여 만든) 각 asynchronus 호출 여기

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); 
    } 
} 

클래스 B는 방법 2를 가지고하는 것은 스레드로부터 안전하지 않은 개체가 있습니다. method2를 실행하는 동안 각 스레드가 고유 한 객체를 갖도록 B의 새 인스턴스를 만들고 싶습니다. 나는 method2에 대한 스프링의 비동기 유틸리티를 사용할 수 있으며 클래스 A에서 CompletableFuture 대신 A에서 비동기 적으로이 메서드를 호출 할 수 있습니다. 그러면 method2 스레드를 안전하게 만들 수 있습니다. CompletableFuture를 사용하면 method2 스레드를 안전하게 만들 수 있습니까? 클래스 B는 스레드로부터 안전하지 않으므로 thread2를 호출하기 위해 스레드를 생성 할 때마다 클래스 B에 대해 다른 객체가 필요하다는 가정이 맞습니까? 여기

+1

생성자 삽입을 사용하고 각 클래스 A 인스턴스에 B 클래스의 삽입 된 인스턴스가 있는지 확인합니다. 클래스 B의 인스턴스를 메서드에 전달하면 , 그것을 전달하는 객체와 마찬가지로 쓰레드 안전합니다. – duffymo

+0

공유 할 수있는 변경 가능한 데이터가 문제입니다. 클래스 A의 모든 상태를 제거합니다. 클래스 B의 인스턴스를 매개 변수로 method()에 전달하면 스레드로부터 안전합니다. – duffymo

+0

코드 샘플을 자세히 설명해 주시겠습니까? –

답변

0

나는 당신이 그것을 할 것을 권 해드립니다 방법은 다음과 같습니다 더 공유 가변 데이터가 없기 때문에

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()); 
    } 
} 

이 안전 스레드입니다. 각 메소드에 전달 된 매개 변수는 독립적입니다.

+0

CompletableFuture에 대한 fork-join 풀에 의해 생성 된 모든 스레드가 여전히 동일한 objB를 사용하기 때문에 문제가 해결되지 않습니다. method2가 호출 될 때마다 B의 다른 인스턴스가 필요합니다. –

+0

아니요, 매번 메서드에 전달한 개체에 대한 참조를 사용합니다. 전화 할 때 다른 참조를 전달하십시오. – duffymo

0

빈의 범위를 프로토 타입으로 설정하는 또 다른 방법입니다. 가장 좋은 방법은 아니지만 이렇게 할 수도 있습니다.

@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 
     } 
    } 
+0

이 솔루션은 내 문제를 해결합니다. 감사합니다. –

+0

클래스 B는 스레드로부터 안전하지 않으므로 thread2를 호출하기 위해 스레드를 생성 할 때마다 클래스 B에 대해 다른 객체가 필요하다는 가정이 맞습니까? –

+1

클래스 B가 스레드 안전하지 않은 경우 스레드를 안전하게 만들거나 모든 스레드에 대해 새 개체를 만들어야합니다. 하지만 가능한 경우 공유 상태를 제거하여 클래스 b 스레드를 안전하게 만드는 것이 가장 좋습니다. –