最近做项目,高并发的情况比较常见,因此常常需要用到多线程。而之前一直对多线程处于一个比较模糊的状态,这次终于清晰了点儿。其实理解多线程可以和异步调用结合起来理解会比较好。
?
对于同步调用和异步调用,可以用以下伪代码来粗略的看一下:
?
同步调用:
public void test() { //某段代码 //这里是入db的操作 this.saveDataToDb(Map params); }
?异步调用:
public void test() { //某段代码 //这里是入db的操作 new Thread(new SaveDataToDb(Map param)).start(); }
?其中SaveDataToDb类是一个实现了Runnable接口的线程。
?
在同步调用中,你必须等待“某段代码”执行完毕后,再执行saveDataToDb操作。而入db是一个相对耗时的操作。在非并发的情形下,这样做性能上的劣势还可能不能体现出来。但当是高并发的情况和不定时被执行的情况下呢?我们总不能执行到saveDataToDb处时,就一直等待saveDataToDb执行完,才开始接收下一次的任务请求吧!所以就必须开启另一个线程。
?
于是就用到了异步调用。把saveDataToDb的逻辑放到一个线程类的run方法里,而当执行到入db的操作处时,我们就启用该线程来“异步”地执行入db的操作。这样,在高并发的情况下,“下一次”的请求就可以不用等到“这一次”入db的操作执行完毕后再执行了。
?
具体到实际情景就是:如果执行某项任务需要甲乙协作完成,甲做完“下一步”给乙做,而乙做的东西又比较耗时,则此次任务必须是甲等待乙完成之后再接收下一次该任务。其中的等待时间就浪费了。如果是异步的话,则甲完成他的部分,可以不必等待乙完成再接收下一次任务。甲每次完成就把他的结果部分丢给乙,而乙是可以不必跟甲在同一流程里执行的。这样就达到了“错开”的效果。也节省了时间。
?
当然,我们更为合理的做法是用一个线程池去控制多线程,线程池可以负责多个线程的创建、等待、调度和销毁等。因为如果在高并发的情况下,你每到入db处,就new一个线程,当new的线程越来越多时,会造成内存的大量占用。
?
拿甲乙的例子来说,线程池就是负责创建了很多个“乙”,他们共同协作完成比较耗时的入db的操作。效率上因此更加高效了。线程池此时可以理解成“包工头”,当一个“乙”做完之后,就可以接着做了,而当一个“乙”正在做,则不会把任务分配给他,只有当他做完之后,才会再次分配入db的任务给他。
?
我们不妨在web项目初始化的时候,就创建一个线程池的类,这个线程池类定义好了一些多线程的配置然后定义一个调度线程的静态方法。我们需要用线程池调用线程时,就调用该静态方法即可。
?
需要注意的是,“异步”调用受线程影响很大。就拿上述的入db操作的线程来说,可能在高并发的情形下,线程未能及时被线程池回收而不够用,入db的操作就会被down掉或不能及时入db。所以需要我们好好控制线程池的配置。
?
原文:http://raising.iteye.com/blog/2244230