1.什么是线程?为什么要用线程池?
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务,线程池都是后台线程。
Java中创建和销毁一个线程是比较昂贵的操作,频繁的创建和销毁线程会影响系统性能。使用线程池可以节省系统的开销,节省创建和销毁线程的时间等。
2.线程池的几个对象
- Executor:Java中的线程池接口,接口中只含有一个void execute(Runnable command)方法,用于执行已提交的线程任务,提供了一种将任务提交和运行的机制,是最顶层接口定义,有多个实现类。
- ExecutorService:继承了Executor接口,在Executor的基础上加入了线程池生命周期管理,一般使用该接口来实现和管理多线程,并且还支持Callable形式的任务。
- void shutdown():关闭当前的线程池,并停止线程池内所有的线程,同时不再接受新的线程提交。
- List<Runable> shutdownNow():停止所有正在执行的任务,停止等待处理的任务,并返回正在等待处理的任务列表。
- boolean isShutdown():判断当前线程池是否关闭。
- boolean isTerminated():如果当前池关闭后所有的任务都完成,则返回true。
- boolean awaitTermination(long timout, @NotNull TimeUnit unit):阻塞线程池,直到所有的任务在关闭请求后都执行完成,或者超时,或者是当前线程中断,以先发生的情况为准,如果请求都执行完成返回true,如果在终止前超时返回false。
- <T> Future<T> submit(Callable<T> task):提交一个Callable类型的线程任务,返回Futrue对象用于描述当前任务状态,提交task不能为空,否则会触发NullPointerException异常;如果任务没有预期执行,也会抛出RejectExecutionException异常。
- <T> Future<T> submit(Runnable task, T result):提交Runable类型的任务,返回Futrue对象用于描述当前任务状态,提交task不能为空,否则会触发NullPointerException异常;如果任务没有预期执行,也会抛出RejectExecutionException异常。如果成功提交任务的话,Futrue对象中code则返回给定的result。
- Future<?> submit(Runnable task):提交Runable类型的任务,返回Futrue对象用于描述当前任务状态,提交task不能为空,否则会触发NullPointerException异常;如果任务没有预期执行,也会抛出RejectExecutionException异常
- <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks):提交所有可执行的Callable类型任务,返回Futrue列表,具有阻塞性,需要等所有的线程任务执行完毕,返回全部任务的结果值。
- List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit):提交所有可执行的callable类型任务,设置超时时间,超出最大等待时间,中断剩余未执行的任务,返回当前执行的TimeUnit对象。具有阻塞性,需要等所有的线程任务执行完毕,返回全部任务的结果值。
- T invokeAny(Collection<? extends Callable<T>> tasks):提交所有可执行的Callable类型任务,第一个任务成功执行后,将其结果作为返回值。
- T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit):提交所有可执行的Callable类型任务,第一个任务成功执行后,将其结果作为返回值。设置超时时间,超出最大等待时间,中断剩余未执行的任务,返回当前执行的TimeUnit对象。
- Eexcutors:线程池工厂类,包含诸如RunnableAdapter、PrivilegedCallable等内部类,包含诸多创建线程池的静态方法,返回的线程池都是ExecutorService接口的实现类,可创建ExecutorService、ThreadFactory、Callable类型的对象。创建线程池的实现也是新建ThreaPoolExecutor对象,使用默认的ThreadPoolExecutor构造方法,创建符合业务的线程池。
- ExecutorService newFixedThreadPool(int nThreads):创建一个在共享无边界队列上运行固定数量线程的线程池,该池上最多有nThread个活动线程,如果在所有线程都活动的情况下提交新的任务,新的任务将在队列中等待线程可用。如果线程池中的某个线程在线程池关闭之前由于失败而终止,则线程池中新的线程将会替代终止的线程继续执行,池中的线程会一直存在,除非显示的调用shutdown()方法。
- ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory):和上面的静态方法一样,唯一不同就是参数列表中多了ThreadFactory对象。
- ExecutorService newSingleThreadExecutor():创建线程数为1的线程池,在任意的时间内只有一个任务在执行,如果该任务在执行过程中失败而终止了,则需要在后续执行中将其替换为新任务。
- ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory):创建线程数为1的线程池,和上面方法作用一直,在需要的时候传递ThreadFactory对象创建新线程。
- ExecutorService newCachedThreadPool():创建一个可缓存的线程池,调用execute将重用之前构造的可用线程,如果没有现有线程可用,则将创建新的线程并将其添加进池中,超过默认时间未使用的线程将被终止并从缓存中移除,因此,空闲时间足够长的池不会消耗任何资源。
- ExecutorService newCachedThreadPool(ThreadFactory threadFactory):作用和上面方法一样,在需要的时候传递ThreadFactory对象创建新的线程。
- ScheduledExecutorService newSingleThreadScheduledExecutor():创建线程数为1的线程池,可以延迟执行,通过新建ScheduledThreadPoolExecutor对象返回线程池对象。
- ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory):创建线程数为1的线程池,可以延迟执行,通过新建ScheduledThreadPoolExecutor对象返回线程池对象,在需要的时候传递ThreadFactory对象创建新的线程。
- ScheduledExecutorService newScheduledThreadPool(int corePoolSize):创建指定线程数量的线程池,可以在指定的时间执行,也可以周期性的执行。
- ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory):创建指定线程数量的线程池,可以在指定的时间执行,也可以周期性的执行,在需要的时候传递ThreadFactory对象创建新的线程。
- callable(Object o):参数可以传入Runnable、PrivilegedAction、PrivilegedExceptionAction等对象,返回Callable对象。
- Callable<T> privilegedCallable(Callable<T> callable):返回 Callable 对象,调用它时可在当前的访问控制上下文中执行给定的 callable 对象。
- Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable):返回 Callable 对象,调用它时可在当前的访问控制上下文中,使用当前上下文类加载器作为上下文类加载器来执行给定的 callable 对象。
- jdk1.8新增的几个方法:
- ExecutorService newWorkStealingPool(int parallelism):创建一个指定线程数的线程池,返回ForkJoinPool对象,该对象是从1.7添加的,继承了ExecutorService,是对ExecutorService的补充,主要是为了实现“分而治之”的算法,特别是分治之后递归调用的函数,最适合于计算密集型的任务,
- ExecutorService newWorkStealingPool():和上面方法一样,只是没有指定线程数。
- ThreaPoolExecutor:线程池的实现,继承了AbstractExecutorService类,该类实现了ExecutorService接口,Executors中静态方法创建线程池大致使用该对象的构造方法,通过改变构造参数来创建不同使用场景的线程池,基本的构造方法如下
/** * * @param corePoolSize:保留在线程池中的数量 * @param maximumPoolSize:线程池中最大的线程数 * @param keepAliveTime:当目前线程数大于最大线程数时,新的线程加入线程池最大等待时间。 * @param unit:超时时间单位,与keepAliveTime共同决定最大超时时间 * @param workQueue:用于任务执行之前保存任务的队列,只包含使用execute()方法提交的任务。 * @param threadFactory:线程工厂类,用于在需要的时候生成新的线程,默认是实现Executors. * defaultThreadFactory(),即new一个Thread对象,设置线程名称, * daemon等属性 * @param handler:当线程边界和队列容量已达而阻止执行时要是用的处理程序,也就是当提交任务 * 时,目前的线程池中已无空闲线程、队列也满了,就会调用handler的 * rejectedExecution方法。 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
如上所示,构造函数中的corePoolSize、maximumPoolSize、keepAliveTime、threadFactory、handler几个属性,在ThreadPoolExecutor中都是使用了valatile关键字修饰,获得原子性,保证了在并发环境下,这几个对象能有正确的表现。
在ThreadPoolExecutor中使用了一些常量去保存线程池运行时的状态,存储在高阶位,在运行时也使用了一些方法根据不同的运行时状态改变常量
// runState is stored in the high-order bits //状态常量 private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; //Packing and unpacking ctl //包厢开箱控制 private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; }
在ThreaPoolExecutor中还存在构造函数的多重表现,上面展示的是其余构造函数调用的根本方法,其余的表现形式如下
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); }