为什么我的@Async Future <t>会阻止?

时间:2017-06-07 07:28:30

标签: java spring spring-mvc asynchronous

我有2个同步方法,下面的方法没有阻止。

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

但以下一个阻止。

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

它们属于同一个控制器类,为什么会出现这种不同的行为?

3 个答案:

答案 0 :(得分:1)

在第二种情况下,您调用内部方法。所以忽略@Async(不调用代理方法)。

有两种方法可以修复

第一个是引入一个单独的bean(例如MyService)并在那里移动带有@Async方法的注释。

第二种方法是将控制器自动装配

@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 :(得分: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);
    }
}

这将以异步方式运行(非阻塞)。

如果要在同一个控制器中执行此操作,可以手动将其提交到某个线程池。

答案 2 :(得分:1)

你有自我调用,直接从方法callAsyn3调用方法sendMail3。它不起作用,因为它绕过代理并直接调用底层方法。 简单修复 - 您应该从上下文获取控制器并从此实例调用callAsyn3。 正常修复 - 创建新服务 - asyncSendMailComponent / Service,将sendMail3移动到asyncSendMailComponent,将asyncSendMailComponent注入您的控制器并调用sendMail3

控制器中的

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