spring注解详解与用法(4)异步相关

 

导航:更多的spring注解标签点击这里

@EnableAsync

开启异步任务支持。注解在配置类上,这个没什么好说的

,可能有的人会问,开启一个子线程的话,我们通过new Thread 或者实现runnable就可以了,为什么要用到这里

其实一般情况下也是如果

EnableAsync是可以提供线程池的,我们需要实现AsyncConfigurer接口才有意义,如果不实现的话那么就和new Thread或者实现runnable接口一样的

使用示例:

@EnableAsync
public class Test implements AsyncConfigurer {
}

我们来看一下AsyncConfigurer 接口的源码

如上图所示,他只提供了2个方法

getAsyncExecutor方法是执行方法,返回线程池的一些信息,
getAsyncUncaughtExceptionHandler则是发生了异常应该处理的方方法
具体配置如下所示:
@EnableAsync
public class Test implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        // TODO Auto-generated method stub
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池数量,方法: 返回可用处理器的Java虚拟机的数量。
        executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
        //最大线程数量
        executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5);
        //线程池的队列容量
        executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*2);
        //线程名称的前缀
        executor.setThreadNamePrefix("this-excutor-");
        // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
        // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
        //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
    /*异步任务中异常处理*/
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

由于代码中注释已经很详细了,这里我就不再次阐述了

@Async

注解在方法上标示这是一个异步方法,在类上标示这个类所有的方法都是异步方法,执行线程池就是我们上面配置的

这个也没有什么好说的,使用如下所示

@Component
public class TreadTasks {
    @Async
    public void startMyTreadTask() {
        System.out.println("这是一个异步线程");
    }
}

使用也很简单,如下所示

@RestController
public class Web {
    @Autowired
    private TreadTasks treadTasks;
    @RequestMapping("a123")
    public String aaa(){
        treadTasks.startMyTreadTask();
        return "111111";
    }
}

执行效果如下所示

这个线程池是不是非常简单?

确实是很简单,网上绝大部分都是这么说的,但是呢,这里面有一个有意思的问题,那就是这么做其实是错误

这样写并不是一个异步线程,而是同一个线程,下面我们就来证明一下这个错误,我们修改一下代码,如下所示

 

运行测试一下

我们可以看到,两个线程的id是一模一样的,根本就不是一个异步线程,如果还不信的话我们看看下面的代码

加了一个打印语句

线程等待一会在执行

我们可以看到,虚拟机数量那一句根本没有打印,而且先打印了异步线程id,说明这并不是一个异步。

那么到底是怎么回事呢?spring提供的有问题?

当然不是,因为EnableAsync标签根本就不是一个全局的标签,他和@RestController类似,只是表明本类而已,所以我们需要把EnableAsync放到具体的类上才是一个正确的异步,如下所示

而且线程池需要的标签也不是EnableAsync,而是Component

这样才是正确的,执行效果如下所示

我们可以看到,打印了虚拟机的数量,而且两个线程的id也不一样

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章