`
z19910509
  • 浏览: 49733 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

浅谈多线程在java程序中的应用

    博客分类:
  • java
阅读更多

在一个高并发的网站中,多线程是必不可少的。下面先说一下多线程在程序中的作用。

1、提高前端请求的响应速度。当我们执行一个比较耗时的方法时,http请求得不到响应甚至会超时,这时如果业务上允许数据的延迟,我们可以使用多线程来进行处理比较耗时的方法。这样前端发送了请求,后端令开启了一个线程去处理任务,就不会阻塞主线程了。

2、减清服务器的压力。包括我们的web容器,如tomcat、jetty等,还有数据库服务器等。因为我们使用了多线程,并且线程池大小有限制,如30,那么同时请求数据库的链接就限制为30了,也就是说能够同时执行方法的线程只有30个,其余的任务都放在我们线程的任务队列了,这样数据库就不会被突然上来的请求给压垮了。当然对于缓解数据库压力来说,更建议使用消息队列,使用消息队列我们可以攒数据进行批量提交,而仅仅使用多线程,则不好实现攒数据的过程。

3、提高处理能力,增加性能,充分利用服务器资源。如我们要将三个表里的数据加载到缓存,最简单的我们一个表开启一个线程,共用三个线程去加载缓存则比用一个线程去挨着遍历三个表的数据高效的多。

 

当然,多线程给我们带来好处的同时,也有许多要注意的地方

1、既然我们使用了多线程,那我们就对数据的实时性不那么严格,包括方法的返回值、数据的入库操作等。所以说,使用多线程的方法一定要做好日志记录,因为发生了异常,前端是反馈不到的。当然,多线程也是可以有返回值的,可以返回Future,里面的get方法可以阻塞到该线程执行完毕。

2、我觉得最烦人的是,为了提高性能,程序必须使用多线程或者其他异步操作,但还必须保证用户体验,如用户进行修改操作,这个修改操作我们是异步的,要求用户在前端还必须立刻看到修改的结果。这样就需要前后端同时去努力了。

3、非常重要的一点就是线程安全的问题了,如我们对一个集合的数据进行修改,在多线程高并发情况下,如果处理不好,可能会出现些我们意想不到的结果。即使我们没有使用多线程,在高并发情况下,线程安全问题是我们必须要重视。举个例子说吧,在我们进行压力测试的时候,当登陆人数压到10w的时候,读取分页列表的时候老是抱些奇怪的异常,但压得人数少了,或者说我们自己单独测试,则不会出现异常。检查一看,原来是我们使用的某个分页插件里有一个判断某个集合是否为空,如果为空则初始化的操作,因为这个集合是全局变量,所以人一多,就会出现线程安全问题。

4、对于自己不确定有多少线程的操作,一定要使用线程池,不然不但提高不了性能,反而会降低性能,甚至会导致jvm内存满了。

5、对于线程池大小的问题,也有很多说明这些问题的文章,什么区分是io还是cpu密集型的,我认为也不必非要那么严格去计算出那么一个数,测试达到自己的要求即可。

 

上面说了一堆乱七八糟的理论,下面说一下java程序中如何使用线程池,

1、可以直接使用new ThreadPoolExecutor()去创建,但此方法比较麻烦,如没有特殊需求,不建议使用该方法

 

2、使用java提供的Executors类去创建一个线程,我们比较常用的,如:

ExecutorService executor=Executors.newFixedThreadPool(10);//通过该方法则创建了一个大小为10,且任务队列无界的线程池,其实该方法本质也是调用方法1中的方法。Executors中还可以创建其他类型的线程,如Executors.newCachedThreadPool(),Executors的具体使用这里不再进行叙述。

 

3、spring也给我们提供了比较方便的线程池初始化方法,当然它本质也是调用1中的方法。使用方法如下:

 <!-- 在spring扫描的配置文件里加入以下配置,则声明了一个大小为5的线程池 -->
 < task:executor id="addnotic" pool-size="5"/>

在java程序中,我们通过@Autowired或@Resource注入即可,如

@Resource(name="addnotic")
private ThreadPoolTaskExecutor addnotic_executor;

 

因为我们项目使用了spring,所以对于线程池我们一般都是使用方法3中的方法使用的,挺方便的。

 

 

 本文内容大体就这些,若大家觉得说的有什么不好的地方,请指正,谢谢

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics