面试--线程(二)线程池

线程池类型,创建,核心参数,配置,阻塞队列的不同类型

https://www.jianshu.com/p/210eab345423点击打开链接

http://ifeve.com/java-threadpool/点击打开链接

1什么是线程池?

指  在初始化一个多线程应用程序的过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是创建新的线程。

2:为什么使用线程池

    1:创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率

    2:线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况,运用线程池能有效的控制线程最大并发数

    3:对线程进行一些简单的管理,比如:延时执行、定时循环执行的策略等

合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

 3:创建:

我们可以通过ThreadPoolExecutor来创建一个线程池。

1 new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
2 keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);
4:对线程池的配置,就是对ThreadPoolExecutor构造函数的参数的配置

1  -----int corePoolSize => 该线程池中核心线程数最大值

  • corePoolSize(核心线程池,线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程,核心线程默认情况下会一直存活在线程池中,即使这个核心线程啥也不干(闲置状态)。如果指定ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true,那么核心线程如果不干活(闲置状态)的话,超过一定时间(时长下面参数决定),就会被销毁掉,很好理解吧,正常情况下你不干活我也养你,因为我总有用到你的时候,但有时候特殊情况(比如我自己都养不起了),那你不干活我就要把你干掉了。

2--- int maximumPoolSize  =>  线程池最大大小 , 线程总数最大值            线程总数 = 核心线程数 + 非核心线程数
                                              线程池允许床架最大线程数,它表示在线程池中最多能创建多少个线程;
如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果使用了无界的任务队列这个参数就没什么效果。

3---long keepAliveTime  =>非核心线程闲置超时时长

         一个非核心线程,如果不干活(闲置状态)的时长超过这个参数所设定的时长,就会被销毁掉

  • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

4----TimeUnit(线程活动保持时间的单位):keepAliveTime   可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

5---BlockingQueue<Runnable> workQueue

  • runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。
  1. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
  2. LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
  3. SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
  4. PriorityBlockingQueue:一个具有优先级得无限阻塞队列。

6---ThreadFactory threadFactory:主要用来创建线程,这是一个接口,new他的时候需要实现他的Thread newThread(Runnable r)方法,

7----RejectedExecutionHandler handler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。n  AbortPolicy:直接抛出异常。

  1. CallerRunsPolicy:只用调用者所在线程来运行任务。
  2. DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
  3. DiscardPolicy:不处理,丢弃掉。
  4. 当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

5:

ThreadPoolExecutor的策略

通过ThreadPoolExecutor.execute(Runnable command)方法即可向线程池内添加一个任务

当提交一个新任务到线程池时,线程池的处理流程如下:

首先线程池判断 基本线程池是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程。
  1. 其次线程池判断工作队列是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。
  2. 最后线程池判断整个线程池是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。
  1. 线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务
  2. 线程数量达到了corePools,则将任务移入队列等待
  3. 队列已满,新建线程(非核心线程)执行任务
  4. 队列已满,总线程数又达到了maximumPoolSize,就会由上面那位星期天(RejectedExecutionHandler)抛出异常

常见四种线程池

CachedThreadPool()可缓存线程池:

  1. 线程数无限制  2有空闲线程则复用空闲线程,若无空闲线程则新建线程.。3一定程序减少频繁创建/销毁线程,减少系统开销

创建方法:ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

FixedThreadPool()定长线程池可控制线程最大并发数(同时执行的线程数);超出的线程会在队列中等待

创建方法:ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);

ScheduledThreadPool()      定长线程池:支持定时及周期性任务执行。

创建方法:ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

SingleThreadExecutor()单线程化的线程池有且仅有一个工作线程执行任务。所有任务按照指定顺序执行,即遵循队列的入队出队规则

创建方法:ExecutorService singleThreadPool = Executors.newSingleThreadPool();


二:

     1.线程池状态

  2.任务的执行

  3.线程池中的线程初始化

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

  5.任务拒绝策略

  6.线程池的关闭

  7.线程池容量的动态调整



猜你喜欢

转载自blog.csdn.net/lettyisme/article/details/80954342