醋醋百科网

Good Luck To You!

Executor

一、前言

JDK1.5中提供了Executor接口,处于java.util.concurrent包下;

创建线程的几种方法

  • 创建子类继承Thread类(Thread类实现了Runable接口)并重写run()方法(无返回值),通过子类实例调用start()方法启动;
  • 通过实现Runable()接口并重写run()方法(无返回值),start()方法启动;
  • 创建子类实现Callable()接口,并重写call()方法,提供了2个额外功能:call()方法可以有int返回值call()方法可以声明抛出异常, 由Callable子类对象创建一个FutureTask对象,由FutureTask对象创建一个Thread对象。
  • 通过线程池Executor框架创建
  • 通过spring框架提供的ThreadPoolTaskExecutor创建线程池;

二、ThreadPoolExecutor的构造参数和三种常用线程池

下面是ThreadPoolExecutor类的构造方法

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;
    }

  • int corePoolSize:线程池维护线程的最小数量.
  • int maximumPoolSize:线程池维护线程的最大数量.
  • long keepAliveTime:空闲线程的存活时间.
  • TimeUnit unit: 时间单位,现有纳秒,微秒,毫秒,秒枚举值.
  • BlockingQueue workQueue:任务队列,被提交但尚未被执行的任务
  • threadFactory 表示生成线程池中工作线程的线程工厂,用于创建线程一般默认即可
  • RejectedExecutionHandler handler: 拒绝策略,用来拒绝一个任务的执行,有两种情况会发生这种情况。

ThreadPoolExecutor的处理流程如下:

  • 当池子大小小于corePoolSize就新建线程,并处理请求
  • 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理
  • 当workQueue放不下新入的任务时,新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理
  • 另外,当池子的线程数大于corePoolSize的时候,多余的线程会等待keepAliveTime长的时间,如果无请求可处理就自行销毁。其会优先创建 CorePoolSiz 线程, 当继续增加线程时,先放入Queue中,当 CorePoolSiz 和 Queue 都满的时候,就增加创建新线程,当线程达到MaxPoolSize的时候,就会抛出错 误 org.springframework.core.task.TaskRejectedException。另外MaxPoolSize的设定如果比系统支持的线程数还要大时,会抛出java.lang.OutOfMemoryError: unable to create new native thread 异常。

FixedThreadPool

固定线程池的线程数量是固定的,由传入的参数决定。线程 keepAliveTime 为0,即不会因为空闲超时而关闭线程,同时队列是无边界的队列,不会发生任务丢弃。

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

CachedThreadPool

单线程池中线程数量固定为1.

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

SingleThreadPoolExcutor

缓存线程池的核心线程corePoolSize 数量为0,但是池中的最大线程数是 无边界。空闲超时为60s,队列用了SynchronousQueue,即任务是立即交付运行的。

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

我们参考阿里巴巴的Java开发手册内容:
8. 【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors各个方法的弊端:
1) newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2) newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
9. 【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。

三、ScheduledThreadPoolExecutor

推荐使用
ScheduledThreadPoolExecutor替代Timer

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言