线程池

什么是线程池?

线程池是基于对象池的思想,开辟一块内存空间,里面存放了众多线程,池中线程的调度交给池管理器来管理

为什么要使用线程池?

在并发任务很多的情况下,每一个线程执行很短的时间就结束了,线程频繁地创建和销毁会大大减低系统的性能,我们创建一个线程池,

当任务需要执行时,线程池会分配一条线程池中的线程去处理此任务,处理完以后放回池中继续去处理其他任务,,使线程得到复用。

java中的ThreadPoolExecutor类:

ThreadPoolExecutor构造器中各个参数的含义:

corePoolSize:核心池线程数的大小,创建线程池时,默认情况下线程池中并没有线程,直到有任务到来时才去创建线程去处理任务,除非调用

preStartAllCoreThreads()和preStartCoreThread()方法(分别创建corePoolSize个线程和一个线程),当池中的线程数达到核心池的最大线程数是,

就会把放到的任务当道缓存队列中;

maximumPoolSzie:线程池中允许的最大线程数,当线程池中的线程数大于核心池线程数并且阻塞队列已满,如果此时线程池中的最大线程数还没有达到

maximumPoolSize,那么将会新创建一个线程去处理此任务。

KeepAliveTime:线程处于空闲状态的最大存活时间,默认只有在线程池中的线程数超过corePoolSize才有用,会将线程池中处于空闲状态持续超过KeepAliveTme

的线程,直到池中的线程数不大于corePoolSize,即核心池的线程数。

unit:KeepAliveTime的时间单位

workQueue:存放任务的阻塞队列,有几种参数的选择,下面会细讲。

threadFactory:线程 工厂

handler:拒绝处理任务时的策略;

ThreadPoolExecutor有几个非常重要的方法:

executor(Runnable commad):最顶层接口Executor唯一声明的方法,调用此方法向线程提交一个任务,交给线程去执行。

shutDown():将线程池的状态置为SHUTDOWN,相当于关闭线程,将不再接受新的任务,等待阻塞队列中的任务执行完毕。

shutDownNow():将线程池的状态置为STOP,线程池将不会接受新的任务,并尝试终止当前执行的任务。

线程池几种状态:

1.RUNNING

2.SHUTDOWN

3.SHUTDOWNOW

4.TERMINALS:当线程池处于stop或shutdown状态并且所有工作线程已被销毁,阻塞已经清空,线程池状态将被置为terminals;

任务的执行过程:

1.将任务提交给线程池,即调用executor(Runnable command)方法,当任务为空时抛出空指针异常。

2.判断当前线程数是否大于核心池线程数,如果大于,会将任务尝试添加到阻塞队列中,排队等待空闲的线程取出执行,如果添加失败,

会尝试创建新的线程去执行,如果当前线程池中的线程数大于maximumPoolSize,线程池会采取任务拒绝策略(丢弃任务抛出异常等)

3.当前线程数小与核心池的线程数,那么就会调用addIfUnderCoreSize(Runnable command)这个方法,这个方法会去创建工作线程去执行当前任务,

将创建工作线程的操作放在使用Lock锁的同步块中,防处理同一任务的工作线程被多次创建,在工作线程的run()方法中有 一个while循环,当前工作线程

执行完当前任务以后,会继续到阻塞队列中取出任务执行,直到取不到任务,然后根据当前线程池的状态决定当前工作线程是否退出。

4.任务缓存队列及排队策略

workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型:

1.直接提交策略:缓存队列使用synchronousQueue(同步队列)

ExcutorService cachedThreadPool=Executors.newCachedThreadPool(),默认线程池的最大线程数为Integer.MAX_VALUE,KeepAliveTime为60s,

提交任务时,任务不会进入队列,而是判断线程池中是否有一个空闲来处理该队列,如果有则入队,如果没有,则去创建一个线程来处理此任务,

适用于负载较轻的服务器。

2)无界策略使用LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE,默认KeepAliveTime为0,指定线程池最大允许的线程数

ExecutorService pool = Executors.newFixedThreadPool(最大允许线程数);

3)有界队列使用ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小,不提倡此种策略,当并发量大时,有可能造成资源耗尽。

线程池的四种拒绝策略:

1.丢弃任务并抛出异常

2.丢弃任务不抛出异常

3.丢弃队列中最老的任务

4.将任务交给调用的线程执行

 

  

 

 

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

posted @ 2018-03-11 18:52  大熊好好写代码  阅读(175)  评论(0编辑  收藏  举报