【多线程】——三种线程池ThreadPoolExecutor

Execurtor框架最核心的类是ThreadPoolExecutor,他是线程池的实现类,主要有四个构建

  • corePool:核心线程池的大小
  • maximumPool:最大线程池的大小
  • BlockingQueue:用来暂时保存任务的工作队列
  • keepAliveTime:非核心线程闲置超时时间
FixedThreadPool详解

FixedThreadPool被称为可重用固定线程数的线程池。源代码实例如下

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

FixedThreadPool的corePoolSize和maximumPoolSize都被设置为创建FixedThreadPool的指定参数nThread。当线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的最长时间,超过这个时间后多余的线程将被终止。这里的keepAliveTime设置为0L,意味着多余的空闲线程会立即停止。
FixedPoolExecutor

SingleThreadExecutor详解

SingleThreadExecutor是使用单个worker线程的Executor。源码如下

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

SingleThreadExecutor的corePoolSize和maximumPoolSize被设置为1,其他参数与FixedThreadPool相同。SingleThreadExecutor使用无界队列LinkedBlockingQueue作为线程池的工作队列(队列的容量为Integer.MAX_VALUE)。SingleThreadExecutor使用无界队列作为工作队列对线程池带来的影响与FixedThreadPool相同。
SingleThreadExecutor

CachedThreadPool详解

CachedThreadPool是一个会根据需要创建新线程的线程池。创建源码

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

CachedThreadPool的corePoolSize被设置为0,即corePool为空;maximumPoolSize被设置成Integer.MAX_VALUE,即maximumPool是无界的。这里吧keepAliveTime设置为60L,意味着CachedThreadPool中的空闲线程等待新任务的最长时间为60s,空闲线程超过60s将会被终止。
FixedThreadPool和SingleThreadExecutor使用无界队列LinkedBlockingQueue作为线程工作队列。CachedThreadPool使用没有容量的SynchronousQueue作为线程池的工作队列,但是CachedThreadPool中maximumPool是无界的。这意味着,如果主线程提交任务的速度高一maximumPool中线程处理任务的速度时,CacheThreadPool会不断创建线程。极端情况下CachedThreadPool会因为创建过多线程而耗尽CPU和内存资源。

线程池中任务排队策略
  • 直接提交(SynchronousQueue):表示线程池不对任务进行缓存。新进的任务会直接提交给线程池,当线程池中没有空闲线程时,创建一个新的线程处理此任务。这种策略需要线程池具有无限增长的可能性。
  • 有界队列(如ArrayBlockingQueue):当线程池中线程达到corePoolSize是,新进任务被放在队列里面排队等待处理。有界队列有助于防止资源耗尽,但是可能较难调整和控制。
  • 无界队列(LinkedBlockingQueue):将导致在所有corePoolSize线程都忙时新任务在队列中等待。这样就不会创建的线程超过corePoolSize。每个任务独立于其他任务,即任务执行互不影响是,适合于使用无界队列。
线程池的拒绝策略
  • CallerRunsPolicy:线程调用运行该任务的execute本身。该策略提供简单的反馈控制机制,能够减缓新任务的提交速度。这个策略显然不想放弃执行任务,由于池中没有任何资源了,那么就直接调用该execute的线程本身来执行。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
               public CallerRunsPolicy() { }

            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

  • AbortPolicy:处理程序操刀拒绝将抛出运行时异常RejectedExecutionException。这种策略直接抛出异常,丢弃任务
public static class AbortPolicy implements RejectedExecutionHandler {
               public AbortPolicy() {         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • DiscardPolicy:不能执行的任务将被删除,这种策略与AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常
public static class DiscardPolicy implements RejectedExecutionHandler {
               public DiscardPolicy() { }

                public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序,在pool没有关闭的前提下,首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
               public DiscardOldestPolicy() { }

               public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

在一般的开发中,我们会自定义拒绝策略。

线程池的具体使用
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值