线程池

193 阅读4分钟

参考:https://www.jianshu.com/p/87bff5cc8d8c

https://blog.csdn.net/tuke_tuke/article/details/51353925


线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池可以对线程进行统一的分配、调优和监控,并有以下好处:

1、降低资源消耗;2、提高响应速度;3、提高线程的可管理性。Java1.5引入的Executor框架把任务的提交和执行进行解耦,只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行、被哪个线程执行,以及什么时候执行。

ThreadPoolExecutor

Executors是java线程池的工厂类,通过它可以快速初始化一个符合业务需求的线程池,如Executors.newFixedThreadPool

(1)ExecutorService e1= Executors.newCachedThreadPool(); //创建一个缓存线程池,线程池容量大小为Integer.MAX_VALUE

(2)ExecutorService e2= Executors.newSingleThreadExecutor(); //创建容量为1的线程池

(3)ExecutorService e3= Executors.newFixedThreadPool(int); //创建固定容量大小的线程池


向线程池提交任务的两种方式:

1)通过execute()方法

e1.execute(new Runnable(){...})

这种方式提交
没有返回值,也就不能判断任务是否被线程池执行成功

2)通过submit()方法

Future<?> future = e1.submit(new Runnable(){...});

  try {

       Object res = future.get();//  获取任务执行结果

   } catch (InterruptedException e) {

       e.printStackTrace(); //处理中断异常

   } catch (ExecutionException e) {

       e.printStackTrace();//处理无法执行任务异常

   }finally{

       executor.shutdown(); //关闭线程池

   }

使用submit 方法来提交任务,
它会返回一个
Future对象,通过future的get方法来获取返值,get方法会阻塞住直到任务完成,而使用get(long timeout, TimeUnit unit)方法则会阻塞一段时间后立即返回,这时有可能任务没有执行完。

corePoolSize

线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。

maximumPoolSize

线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执任务,前提是当前线程数小于maximumPoolSize;

keepAliveTime

线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间;默认情况下,该参数只在线程数大于corePoolSize时才有用;

workQueue

用来保存等待被执行的任务的阻塞队列,且任务必须实现
Runable接口,在JDK中提供了如下阻塞队列:
1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene
3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
4、priorityBlockingQuene:具有优先级的无界阻塞队列;

threadFactory

线程工厂,主要用来创建线程。

RejectedExecutionHandler handler

任务拒绝策略

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

  默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会创建线程。

  在实际中如果需要线程池创建之后立即创建线程,可以通过以下两个方法办到:

· prestartCoreThread():初始化一个核心线程;

· prestartAllCoreThreads():初始化所有核心线程

线程池的实现原理

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

1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。

2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。