controller 是单例模式还是多例模式
springmvc controller默认的是单例singleton的,单例模式是spring推荐的配置,它在高并发下能极大的节省资源,提高服务抗压能力。采用单例模式的好处:
- 为了性能,单例不用每次都new,当然快了。
- 不需要多例,这是官方说法。
单例模式下容易出现的问题就是controller中定义很多的属性,那么单例肯定会出现竞争访问,不同用户共享数据变量是不安全的。因此:
- 不要在controller中定义成员变量。
- 万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式。
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- 在Controller中使用ThreadLocal变量
当然可以修改controller 为多列模式,通过@controller之前增加@Scope("prototype"),或者配置文件定义修改。
Struts2默认的实现是Prototype模式,Struts2中的Action因为会有User、BizEntity这样的实例对象,是有状态信息的,在多线程环境下是不安全的,所以是多例。
单例模式下的高并发线程池处理
在很多场景都会遇到高并发情况:"短时间内遇到大量操作请求"。主要发生在web系统集中大量访问或者socket端口集中性收到大量请求。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。处理不好,可能导致系统宕机,严重的甚至导致OOM异常,系统停止工作等。
实际工作,我们可以使用线程池技术作为处理高并发的手段之一,解决部分问题。
比如:查询推荐商品数据接口,请求此接口访问高并发,并且接口返回数据时间长,在这种高并发的情况下不使用线程池:
- 可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”(1W请求同时执行,创建1W线程),导致宕机。
- 接口查询速度本身就慢,又同时访问对数据库服务器造成很大的压力。
如果使用线程池,能解决以下问题:
- 有效的降低了线程创建释放的时间花销及资源开销。
- 有效控制最大并发线程数,降低了同时请求数(线程池设置线程数量上限,超过则排队等候)。
- 充分重复利用线程。
例如:
//工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE)
//如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
private ExecutorService threadPoolExecutor = Executors.newCachedThreadPool();
private Future<APIGoodsRecommendResponse> getAPIGoodsRecommendResponse(final APIGoodsRecommendRequest apiGoodsRecommendRequest)
{
return threadPoolExecutor.submit(new Callable<APIGoodsRecommendResponse>() {
@Override
public APIGoodsRecommendResponse call() throws Exception
{
return indexService.getGoodsRecommend(apiGoodsRecommendRequest);
}
});
}
高并发下选取什么样的线程池会比较合理(补充)
高并发,低耗时
建议少线程,只要满足并发即可;例如并发100,线程池可能设置为10就可以。如果线程太多,有可能出现线程切换和管理的时间,大于任务执行的时间,那效率就低了。
低并发,高耗时
建议多线程,保证有空闲线程,接受新的任务;例如并发10,线程池可能就要设置为20;
高并发,高耗时
要分析任务类型,增加排队,加大线程数
网友评论