2017-06-07 6 views
0

私は2つの同期メソッドを持っていますが、次のものはブロックしません。なぜ私の@Async Future <T>ブロック?

@RequestMapping("/send1") 
    @Async 
    public Future<Boolean> sendMail() throws InterruptedException { 
     System.out.println("sending mail 1..-" 
       + Thread.currentThread().getName()); 
     Thread.sleep(1000 * 16); 
     System.out.println("sending mail 1 completed"); 
     return new AsyncResult<Boolean>(true); 
    } 

しかし、以下の1ブロック。

@RequestMapping("/send3") 
    public void callAsyn3() throws InterruptedException, ExecutionException { 
Future<Boolean> go = sendMail3("test"); 
} 

@Async 
public Future<Boolean> sendMail3(String msg) throws InterruptedException { 
     boolean acceptedYet = false; 
     Thread.sleep(1000 * 12); 
     if (!msg.equalsIgnoreCase("")) { 
      acceptedYet = true; 
     } 
     return new AsyncResult<>(acceptedYet); 
    } 

これらは同じコントローラクラスに属していますが、なぜこのような動作が異なるのですか?

+1

: 通常の修正は - 、asyncSendMailComponentにsendMail3を移動し、asyncSendMailComponent /サービスをおコントローラにasyncSendMailComponentを注入し、コントローラにsendMail3

を呼び出す - 新しいサービスを作成しますあなたが内部的に呼び出すメソッド。 '@Async'は無視されます(プロキシされたメソッドは呼び出されません)。 – StanislavL

+0

手動で呼び出す方法は? –

+0

jdkプロキシの代わりにcglibプロキシに切り替える必要がある場合は、何をしたいのですか – JEY

答えて

1

2番目のケースでは、内部的にメソッドを呼び出します。 @Asyncは無視されます(プロキシされたメソッドは呼び出されません)。

最初のものは、別のBean(例えばMyServiceで)をntroduce、そこ@Async方法で注釈移動させることである

を固定するための2つの方法があります。

第二の方法はAutowire自体にコントローラ

@ControllerパブリッククラスMyController {

@Autowired 
private MyController myController; 

@RequestMapping("/send3") 
public void callAsyn3() throws InterruptedException, ExecutionException { 
    Future<Boolean> go = myController.sendMail3("test"); 
} 

@Async 
public Future<Boolean> sendMail3(String msg) throws InterruptedException { 
    boolean acceptedYet = false; 
    Thread.sleep(1000 * 12); 
    if (!msg.equalsIgnoreCase("")) { 
     acceptedYet = true; 
    } 
    return new AsyncResult<>(acceptedYet); 
} 
1

プロキシを通過しない同じクラス内のメソッドを呼び出しています。したがって、同じクラスの中で@Asyncのメソッドを使用することはできず、呼び出しを非同期にすることはできません。

別のサービスを作成してそこに@Asyncメソッドを書き込むことができます。このようなもの

@Service 
public class MyService { 
    @Async 
    public Future<Boolean> sendMail3(String msg) throws InterruptedException { 
     boolean acceptedYet = false; 
     Thread.sleep(1000 * 12); 
     if (!msg.equalsIgnoreCase("")) { 
      acceptedYet = true; 
     } 
     return new AsyncResult<>(acceptedYet); 
    } 
} 

これは非同期(非ブロック)で実行されます。

これを同じコントローラで実行する場合は、手動でスレッドプールに送信できます。

1

あなたは自己呼び出しを持っています。メソッドcallAsyn3からメソッドsendMail3を直接呼び出します。プロキシをバイパスし、基礎となるメソッドを直接呼び出しているため、機能しません。 簡単な修正 - コンテキストからcontollerを取得し、このインスタンスからcallAsyn3を呼び出す必要があります。第二に

@Autowired 
private AsyncSendMailComponent asyncSendMailComponent; 
@RequestMapping("/send3") 
    public void callAsyn3() throws InterruptedException, ExecutionException { 
Future<Boolean> go = asyncSendMailComponent.sendMail3(msg) 
} 

非同期サービス

@Service 
    pubclic class AsyncSendMailComponent { 
    @Async 
    public Future<Boolean> sendMail3(String msg) throws InterruptedException { 
      boolean acceptedYet = false; 
      Thread.sleep(1000 * 12); 
      if (!msg.equalsIgnoreCase("")) { 
       acceptedYet = true; 
      } 
      return new AsyncResult<>(acceptedYet); 
     } 
    } 
関連する問題