Java并发——Executor框架ThreadPoolExecutor详解

ThreadPoolExecutor是Executor接口的一个重要的实现类,是线程池的具体实现,用来执行被提交的任务。

一、ThreadPoolExecutor的创建:

  • 直接创建ThreadPoolExecutor的实例对象,这样需要自己配置ThreadPoolExecutor中的每一个参数:
ThreadPoolExecutor tpe = new ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue);
每个参数的具体设置参见: 点击打开链接
  • ThreadPoolExecutor通过Executors工具类来创建ThreadPoolExecutor的子类FixedThreadPool、SingleThreadExecutor、CachedThreadPool,这些子类继承ThreadPoolExecutor,并且其中的一些参数已经被配置好。
//FixedThreadPoll
ExecutorService ftp = Executors.newFixedThreadPool(int threadNums);
ExecutorService ftp = Executors.newFixedThreadPool(int threadNums, ThreadFactory threadFactory);
//SingleThreadExecutor
ExecutorService ste = Executors.newSingleThreadExecutor();
ExecutorService ste = Executors.newSingleThradPool(ThreadFactory threadFactory);
//CachedThreadPool
ExecutorService ctp = Executors.newCachedThreadPool();
ExecutorService ctp = Executors.newCachedThreadPool(ThreadFactory threadFactory);

关于ThreadFactory接口,参见:点击打开链接


二、ThreadPoolExecutor的子类FixedThreadPool、SingleThreadExecutor、CachedThreadPool详解

FixedThreadPool、SingleThreadExecutor、CachedThreadPool都是通过Executors工厂类中的工厂方法创建的,因此我们对这几个方法进行分析。

1、FixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

应用场景:FixedThreadPool是线程数量固定的线程池,适用于为了满足资源管理的需求,而需要适当限制当前线程数量的情景,适用于负载比较重的服务器。

可以看出它的实现就是把线程池最大线程数量maxmumPoolSize和核心线程池的数量corePoolSize设置为相等,并且使用LinkedBlockingQueue作为阻塞队列,那么首先可以知道线程池的线程数量最多就是nThread,只会在核心线程池阶段创建,此外,因为LinkedBlockingQueue是无限的双向队列,因此当任务不能立刻执行时,都会添加到阻塞队列中,因此可以得到FixedThreadPool的工作流程大致如下:

  • 当前核心线程池总线程数量小于corePoolSize,那么创建线程并执行任务;
  • 如果当前线程数量等于corePoolSize,那么把 任务添加到阻塞队列中;
  • 如果线程池中的线程执行完任务,那么获取阻塞队列中的任务并执行;

*注意:因为阻塞队列是无限的双向队列,因此如果没有调用shutDownNow()或者shutDown()方法,线程池是不会拒绝任务的,如果线程池中的线程一直被占有,FixedThreadPool是不会拒绝任务的。

因为使用的是LinkedBlockingQueue,因此maximumPoolSize,keepAliveTime都是无效的,因为阻塞队列是无限的,因此线程数量肯定小于等于corePoolSize,因此keepAliveTime是无效的;


2、SingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

应用场景:SingleThreadExecutor是只有一个线程的线程池,常用于需要让线程顺序执行,并且在任意时间,只能有一个任务被执行,而不能有多个线程同时执行的场景。

因为阻塞队列使用的是LinkedBlockingQueue,因此和FixedThreadPool一样,maximumPoolSize,keepAliveTime都是无效的。corePoolSize为1,因此最多只能创建一个线程,SingleThreadPool的工作流程大概如下:

  • 当前核心线程池总线程数量小于corePoolSize(1),那么创建线程并执行任务;
  • 如果当前线程数量等于corePoolSize,那么把 任务添加到阻塞队列中;
  • 如果线程池中的线程执行完任务,那么获取阻塞队列中的任务并执行;


3、CachedThreadPool

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

应用场景:CachedThreadPool适用于执行很多短期异步任务的小程序,或者是负载较轻的服务器。

CachedThreadPool使用SynchronizedQueue作为阻塞队列,SynchronizedQueue是不存储元素的阻塞队列,实现“一对一的交付”,也就是说,每次向队列中put一个任务必须等有线程来take这个任务,否则就会一直阻塞该任务,如果一个线程要take一个任务就要一直阻塞知道有任务被put进阻塞队列。

因为CachedThreadPool的maximumPoolSize为Integer.MUX_VALUE,因此CachedThreadPool是无界的线程池,也就是说可以一直不断的创建线程。corePoolSize为0 ,因此在CachedThreadPool中直接通过阻塞队列来进行任务的提交。

CachedThreadPool的工作流程大概如下:

  • 首先执行SynchronizedQueue.offer(  )把任务提交给阻塞队列,如果这时候正好在线程池中有空闲的线程执行SynchronizedQueue.poll( ),那么offer操作和poll操作配对,线程执行任务;
  • 如果执行SynchronizedQueue.offer(  )把任务提交给阻塞队列时maximumPoolSize=0.或者没有空闲线程来执行SynchronizedQueue.poll( ),那么步骤1失败,那么创建一个新线程来执行任务;
  • 如果当前线程执行完任务则循环从阻塞队列中获取任务,如果当前队列中没有提交(offer)任务,那么线程等待keepAliveTime时间,在CacheThreadPool中为60秒,在keepAliveTime时间内如果有任务提交则获取并执行任务,如果没有则销毁线程,因此最后如果一直没有任务提交了,线程池中的线程数量最终为0。
*注意:因为maximumPoolSize=Integer.MAX_VALUE,因此可以不断的创建新线程,这样可能会CPU和内存资源耗尽。
  • 20
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: 好的,我来给您讲解一下Java中的Executor框架。 在Java中,Executor框架是一种用于管理线程的高级工具。该框架允许开发者使用高级的API来管理线程,而无需直接使用底层线程管理机制。 Executor框架中的主要接口是ExecutorExecutorService。Executor接口定义了一个用于执行任务的方法,而ExecutorService则是一个扩展了Executor接口的接口,它提供了一系列管理任务和线程的方法,如提交任务、关闭线程池等。 在Executor框架中,任务被封装为实现了Runnable接口或Callable接口的对象。其中,Runnable接口表示一个没有返回值的任务,而Callable接口则表示一个可以返回结果的任务。这些任务被提交给线程池执行,线程池中的线程会从任务队列中获取任务并执行。 Executor框架提供了多种不同类型的线程池,如FixedThreadPoolCachedThreadPoolSingleThreadPool等。其中,FixedThreadPool是一个固定大小的线程池,CachedThreadPool是一个可以自动扩容的线程池,而SingleThreadPool则是一个只有一个线程的线程池。 除了线程池之外,Executor框架还提供了一些其他的工具类,如ScheduledExecutorService用于定时执行任务、CompletionService用于管理异步任务等。 总的来说,Executor框架是一个非常实用的线程管理工具,它简化了线程管理的复杂性,并提供了多种线程池和工具类,帮助开发者更加方便地管理线程。 ### 回答2: Executor框架Java提供的一个用于管理和调度线程的高级框架。它在java.util.concurrent包下,提供了一组接口和类来处理线程的创建、启动、执行和调度。 Executor框架主要包含了三个核心组件:ExecutorExecutorService和ThreadPoolExecutor。 首先,Executor是一个接口,它定义了一个简单的方法execute(Runnable command),用于执行传入的任务。它隐藏了线程的创建和启动过程,只需要将任务交给Executor,它会在后台自动创建线程并执行任务。 其次,ExecutorService是一个接口,它继承自Executor接口,并增加了一些管理和控制线程的方法。它提供了submit(Callable task)方法,用于提交有返回值的任务,并返回一个Future对象,可以通过该对象获取任务的执行结果。ExecutorService还提供了shutdown()和shutdownNow()方法,用于优雅地停止线程池的运行。 最后,ThreadPoolExecutorExecutorService接口的一个实现类。它实现了一个基于线程池的ExecutorService,可以根据任务的数量和需要的资源动态地创建、回收和管理线程。ThreadPoolExecutor通过内部的任务队列和线程池来实现任务的调度和执行。可以通过调整线程池的参数来控制并发执行的线程数量和线程的优先级。 Executor框架的使用可以提供多线程编程的简化和优化。它可以将任务的提交和执行进行分离,将任务的执行交给线程池管理,从而充分复用线程资源,避免线程创建和销毁的开销。同时,它还提供了任务的调度和控制功能,可以根据需要在多个线程之间进行任务的切换和调度,提高系统的运行效率和资源利用率。 总结来说,在Java中,Executor框架是一个强大的并发编程工具,通过它我们可以方便地管理和控制线程的执行,提高程序的性能和响应速度。 ### 回答3: Executor框架Java中用于管理和调度线程的一个重要框架。它提供了一种简单且高效的方式来执行异步任务,并且能够更好地管理线程池资源。 Executor框架提供了一个Executor接口,该接口定义了一个线程池的基本执行操作。常见的实现类有ThreadPoolExecutor和ScheduledThreadPoolExecutor,它们都是Executor接口的具体实现。 通过Executor框架,我们可以使用线程池执行任务,从而避免了为每个任务创建新线程带来的开销。我们只需要将任务提交给线程池即可,线程池会自动进行线程的创建和管理,实现任务的异步执行。 Executor框架还提供了一些功能丰富的方法,如submit()方法和invokeAll()方法。submit()方法用于提交一个任务并返回一个表示该任务结果的Future对象,我们可以利用Future对象来获取任务的执行结果或取消任务的执行。invokeAll()方法用于同时提交多个任务,并等待所有任务完成。 除了常规的线程池功能外,Executor框架还引入了一些用于定时任务调度的类,例如ScheduledThreadPoolExecutor和ScheduledExecutorService。这些类可以实现任务的定时执行、周期执行以及延迟执行等功能。 总之,Executor框架Java中管理和调度线程的重要工具。它提供了一种高效的线程池资源管理方式,并且提供了一些方便的方法来操作和管理任务的执行。在实际开发中,合理地使用Executor框架可以提高程序的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值