线程池探索之基础篇

Posted 冥oo迹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池探索之基础篇相关的知识,希望对你有一定的参考价值。

线程池探索之基础篇

  • 一、使用线程池的好处

  • 二、线程池的内部实现

  • 三、线程池的工厂类

一、使用线程池的好处:

    
1)重用线程,避免系统频繁地创建和销毁线程

    
2)任务过多时,通过排队避免创建过多线程,减少系统资源的消耗

阿里开发手册中规定:线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。

二、线程池的内部实现:

JDK中线程池的实现类是ThreadPoolExecutor,先来看看其最重要的构造方法:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
 


ThreadPoolExecutor类核心方法execute如下:

public void execute(Runnable command{
    if (command == null)
        throw new NullPointerException();

    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(nullfalse);
    }
    else if (!addWorker(command, false))
        reject(command);
}

ThreadPoolExecutor类的任务调度逻辑如下图:

avatar

核心代码为:

三、线程池的工厂类:

    
ThreadPoolExecutor类来自JDK提供的一套Executor框架,框架结构图如下:

avatar

    
Executor框架提供了各种类型的线程池,其内部都是通过ThreadPoolExecutor来实现的,主要有以下工厂方法:

public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newCachedThreadPool()
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

下面来一一描述上述工厂方法:

  • newFixedThreadPool()方法返回一个固定线程数量的线程池。源码如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>());
}
  • newSingleThreadExecutor()方法返回一个只有一个线程的线程池。源码如下:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(11,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
  • newCachedThreadPool()方法返回一个核心线程数为0,最大线程数为Integer.MAX_VALUE的线程池。源码如下:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
  • newSingleThreadScheduledExecutor方法返回一个ScheduledExecutorService,线程池大小为1。ScheduledExecutorService是在ExecutorService的基础上增加了定时执行任务的功能。源码如下:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}
  • newScheduledThreadPool()方法也返回一个ScheduledExecutorService,但可指定线程池的线程数量。源码如下:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

阿里开发手册中规定:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,避免资源耗尽的风险。

Executors返回的线程池对象的弊端如下:
1) FixedThreadPool和SingleThreadPool:

允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。

2) CachedThreadPool和ScheduledThreadPool:

允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。


以上是关于线程池探索之基础篇的主要内容,如果未能解决你的问题,请参考以下文章

线程池的探索(上)

一脚踩进java之基础篇44——线程池和Callable

一脚踩进java之基础篇44——线程池和Callable

高并发多线程基础之ThreadPoolExecutor源代码分析

线程池的探索(下)

DOM探索之基础详解——学习笔记