首先是单线程
串行执行,每一个任务占用一个线程,其他任务进行等待,前一任务执行完毕之后,执行下一任务.
例: 医生看病人,一个医生(线程),多个病人(任务)排队看病,看完一个再看下一个,
优点;占用资源少;没有多并发的情况;
缺点:效率低下,如果前一任务耗时过长,则下一任务等待太久,可能会导致超时;
然后是多线程
多线程并行执行,多个线程(同时)处理多个任务
例:医生看病人,多个医生同时看病人,让病人排队等候,那个医生看完之后叫号再看下一个病人.
优点:提高了效率,避免了任务之间互相影响,导致超时等问题.
缺点:不能无限制创建线程,否则系统资源消耗太过严重.
线程池
存放线程并对线程进行统一管理,监控和调度的资源池
例:医院(资源池)里面的医生(线程),医院来管理看病的医生,医生负责看病,等到周六日高峰期还可以多调度几个医生来缓解看病压力
优点:加强了对线程的管理,提高了资源利用率,降低了无畏的消耗.资源重复利用
小结: 在一定的范围内创建多个线程可以提高资源的利用率,加强处理性能,但是过多的创建线程会造成系统资源的浪费和消耗,无休止的创建会导致系统崩溃;
结合我自己做过的项目,从ftp下载带有数据的文件,然后对文件进行处理,用到的就是定时线程池 scheduledExecutorService ;
由于生产环境服务器限制,这里创建了三个线程,没5分钟执行一次数据处理,提高了数据处理的效率,但是需要注意的是这个方法中的所有异常必须捕获!否则会导致定时任务停止执行的风险!!
线程池执行任务的生命周期,或者四个步骤:
1.创建:创建线程,准备
2.提交:提交线程到执行队列
3.执行:执行线程.
4.完成:任务执行结束.
线程池的几个参数
public XPThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// ... 省略具体实现
}
corePoolSize:核心线程数;
maximumPoolSize:最大线程数
keepAliveTime:活跃时间
unit:单位
workQueue:工作队列(阻塞队列):分为无界队列,有界队列,同步移交队列
threadFactory:线程工厂
handler:有界队列限制参数,饱和策略
注:在线程池工作时,初始线程是0,没添加一个任务就创建一个线程,直到线程数达到corePoolSize,这是线程就不在创建.但是如果任务继续增加,核心线程数不够用时就会创建临时线程,这时线程数到达maximumPoolSize,当任务处理完毕之后,在过了keepAliveTime活跃时间之后,之前创建的临时线程就会被放入可回收队列,等待回收,直到线程数到达核心线程数量,但是如果到达最大线程之后还是任务过多处理不过来,则剩余的任务就会被放入工作队列,等待执行(据说不一定).
threadFactory参数如果不设置会自动创建一个非守护线程
(守护线程和非守护线程,二者基本没有区别,只是销毁时间不同,守护线程相当于所有非守护线程的保姆,只有所有的非守护线程停止工作之后,守护线程才随着JVM停止,最典型的守护线程(GC))
handler参数是当线程达到最大并且达到有界队列最大值之后的处理饱和策略:分为以下四种:
(拒绝)(提交即执行)(丢弃)(丢弃最旧的任务)