Java线程池以及Executor框架

本文整理自Java并发编程

目录

一、线程池实现原理

线程池执行execute的四种情况:

二、线程池的使用

2.1创建线程池

2.1.1.corePoolSize(线程池基本大小)

2.1.2.runnableTaskQueue(任务队列)

2.1.3.maximumPoolSize(线程池最大数量)

2.1.4.RejectedExecutionHandler(饱和策略)

2.1.5.keepAliveTime(线程活动保持时间)

2.1.6.TimeUnit(线程活动保持时间的单位)

2.2向线程池提交任务

2.2.1.execute():

2.2.2.submit():

2.3.关闭线程池

2.3.1.shutdown:

2.3.2.shutdownNow:

三、Executor框架

3.1结构

3.1.1.任务:

3.1.2.任务的执行:

3.1.3.异步计算结果:

3.2成员

3.2.1Runnable 、Callable:

3.2.2ThreadPoolExecutor:

3.2.3ScheduledThreadPoolExecutor:

3.2.4FutureTask:


线程池的好处:

1.降低资源消耗

2.提高响应速度

3.提高线程可管理性

一、线程池实现原理

线程池执行execute的四种情况:

1.如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(需获取全局锁)

2.如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue

3.如果无法将任务加入BlockingQueue(已满),则创建新线程处理任务(需获取全局锁)

4.如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution方法

二、线程池的使用

2.1创建线程池

通过new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);创建一个线程池。

参数:

2.1.1.corePoolSize(线程池基本大小)

当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建新线程,等到需要执行的任务数大于线程池基本大小就不再创建。

2.1.2.runnableTaskQueue(任务队列)

ArrayBlockingQueue:基于数组的有界阻塞队列,FIFO

LinkedBlockingQueue:基于链表的阻塞队列,FIFO

SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态

PriorityBlockingQueue:具有优先级的无限阻塞队列

建议使用有界队列。

2.1.3.maximumPoolSize(线程池最大数量)

如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。

2.1.4.RejectedExecutionHandler(饱和策略)

当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理新提交的任务。

AbortPolicy:直接抛出异常,默认策略

CallerRunsPolicy:只用调用者所在线程来运行任务

DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务

DiscardPolicy:不处理,丢弃掉

也可以实现RejectedExecutionHandler接口自定义策略

2.1.5.keepAliveTime(线程活动保持时间)

线程池的工作线程空闲后,保持存活的时间

2.1.6.TimeUnit(线程活动保持时间的单位)

可选:DAYS,HOURS,MINUTES,MILLSECONDS,MICROSECONDS,NANOSECONDS

2.2向线程池提交任务

2.2.1.execute():

用于提交不需要返回值的任务

2.2.2.submit():

用于提交需要返回值的任务,线程池会返回一个future对象。通过future对象可以判断任务是否执行成功,通过future的get方法获取返回值。

2.3.关闭线程池

2.3.1.shutdown

将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程

2.3.2.shutdownNow

首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表

三、Executor框架

3.1结构

Executor框架主要有3部分组成:

3.1.1.任务

Runnable接口和Callable接口

3.1.2.任务的执行

核心接口Executor,继承Executor的ExecutorService接口。以及两个ExecutorService的实现类ThreadPoolExecutorScheduledThreadPoolExecutor

3.1.3.异步计算结果

Future接口和实现Future接口的FutureTask

主线程创建实现Runnable或Callable接口的任务对象,Executors可以把Runnable封装成Callable

把任务对象交给ExecutorService执行

如果执行submit,ExecutorService将返回FutureTask对象

主线程可以执行FutureTask.get方法等待任务执行完成,也可以执行FutureTask.cancel取消任务执行

3.2成员

3.2.1Runnable 、Callable:

两者的实现类都可以被执行,区别:

Runnable不会返回结果

Callable可以返回结果

可以把Runnable包装成Callable

3.2.2ThreadPoolExecutor:

框架核心类,线程池的实现类。通过Executor框架的工具类Executors,可创建三种类型的ThreadPoolExecutor:

1.FixedThreadPool(可重用固定线程数的线程池)

/**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

corePoolSize和MaximumPoolSize都设置为参数nThreads

keepAliveTime设置为0L,说明多余的空闲线程会被立即终止

任务队列使用无界队列(队列容量为Integer.MAX_VALUE),说明:

public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
}

1)线程数到达core后,新任务将在无界队列中等待,因此线程数不会超过core

2)maximum是无效参数

3)keepAliveTime是无效参数

4)运行中的Pool不会拒绝任务

2.SingleThreadExecutor(使用单个worker线程的Executor)

   /**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue. (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newFixedThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

core和maximum都设置为1.如果线程池中无运行的线程,则创建新线程执行任务,之后的任务都加入到队列中,线程执行完任务后,会在一个无限循环中反复从队列中获取任务。

3.CachedThreadPool(根据需要创建新线程的线程池)

    /**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available.  These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * Calls to {@code execute} will reuse previously constructed
     * threads if available. If no existing thread is available, a new
     * thread will be created and added to the pool. Threads that have
     * not been used for sixty seconds are terminated and removed from
     * the cache. Thus, a pool that remains idle for long enough will
     * not consume any resources. Note that pools with similar
     * properties but different details (for example, timeout parameters)
     * may be created using {@link ThreadPoolExecutor} constructors.
     *
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

core设置为0,即corePool为空

maximum设置为Integer.MAX_VALUE,即maximumPool是无界的

keepAliveTime设置为60L,说明空闲线程等待新任务的最长时间是60秒,超过60秒空闲线程将被终止

任务队列使用没有容量的SynchronousQueue,意味着如果主线程提交任务的速度超过maximumPool中线程处理任务速度时,会不断创建新的线程。极端情况下会因为创建过多线程而耗尽CPU和内存资源

3.2.3ScheduledThreadPoolExecutor:

a.继承自ThreadPoolExecutor。主要用来在给定的延迟之后运行任务,或者定期执行任务。

1)调用ScheduledThreadPoolExecutor的scheduleAtFixedRate()方法或者scheduleWithFixedDelay()方法时,会向DelayQueue中添加一个实现了RunnableScheduleFutur接口的ScheduledFutureTask

2)线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务

b.为了实现周期性执行任务,对ThreadPoolExecutor做了如下修改:

1)使用DelayQueue作为任务队列(无界)

2)获取任务方式不同

3)执行周期任务后,增加额外处理

c.ScheduledFutureTask主要包含3个成员变量

1)long型成员变量time,表示任务将要被执行的具体时间

2)long型成员变量sequenceNumber,表示任务被添加到ScheduledThreadPoolExecutor中的序号

3)long型成员变量period,表示任务执行的间隔周期

d.DelayQueue封装了一个PriorityQueue,这个会对队列中的ScheduledFutureTask进行排序

1)time小的排在前面,也就是时间早的先被执行

2)如果时间相同,sequenceNumber小的排在前面,也就是执行时间相同,先提交的任务先被执行

e.ScheduledThreadPoolExecutor中线程执行某个周期任务的4个步骤:

1)线程从DelayQueue中获取已到期的ScheduledFutureTask(DelayQueue.take())。到期指的是ScheduledFutureTask的time大于等于当前时间

2)线程执行ScheduledFutureTask

3)线程修改ScheduledFutureTask的time变量为下次将要被执行的时间

4)线程把这个修改time之后的ScheduledFutureTask放回DelayQueue中(DelayQueue.add())

3.2.4FutureTask:

FutureTask除了实现Future接口之外,还实现了Runnable接口。因此FutureTask可以交给Executor执行,也可以调用线程直接执行(FutureTask.run())。根据该方法执行的时机,FutureTask可处于3种状态:

1)未启动。run方法执行前

2)已启动。run方法执行过程种

3)已完成。run方法执行正常结束,或被取消(FutureTask.cancel(...)),或异常结束

使用:

1)交给Executor执行

2)通过ExecutorService.submit(...)返回一个FutureTask,然后执行FutureTask的get或cancel方法

3)单独使用FutureTask

发布了82 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/a972669015/article/details/100167851