前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK源码分析 线程池

JDK源码分析 线程池

作者头像
Yano_nankai
发布2018-10-08 10:40:01
2930
发布2018-10-08 10:40:01
举报
文章被收录于专栏:二进制文集二进制文集

说明

对于JDK源码分析的文章,仅仅记录我认为重要的地方。源码的细节实在太多,不可能面面俱到地写清每个逻辑。所以我的JDK源码分析,着重在JDK的体系架构层面,具体源码可以参考:http://www.cnblogs.com/skywang12345/category/455711.html

架构图

Executor 函数接口

Executor:提供一种将"任务提交"与"任务如何运行"分离开来的机制。

代码语言:javascript
复制
void execute(Runnable command)

ExecutorService

ExecutorService提供了"将任务提交给执行者的接口(submit方法)","让执行者执行任务(invokeAll, invokeAny方法)"的接口等等。

AbstractExecutorService

抽象类,为ExecutorService中的函数接口提供了默认实现。

ThreadPoolExecutor

大名鼎鼎的“线程池”。

ScheduledExecutorService

接口,提供了“延时”和“周期执行”接口。

ScheduledThreadPoolExecutor

继承于ThreadPoolExecutor,并且实现了ScheduledExecutorService接口。它相当于提供了"延时"和"周期执行"功能的ScheduledExecutorService。

Executors

静态工厂类。它通过静态工厂方法返回 ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 等类的对象。

示例

代码语言:javascript
复制
class MyThreadPool extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running... ");
    }
}

@Test
public void testThreadPoolExecutor() throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(2);
    for (int i = 0; i < 5; i++) {
        TimeUnit.SECONDS.sleep(2);
        pool.execute(new MyThreadPool());
    }
    pool.shutdown();
}

输出:

代码语言:javascript
复制
pool-1-thread-1 is running... 
pool-1-thread-2 is running... 
pool-1-thread-1 is running... 
pool-1-thread-2 is running... 
pool-1-thread-1 is running... 

分析:

示例代码中,新建了一个大小固定为2的线程池,并将5个线程依次放入线程池。从输出结果中可以看出,是线程pool-1-thread-1和线程pool-1-thread-2相互交替,并没有新建多余的线程。

静态工厂类

代码语言:javascript
复制
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

创建一个线程池,线程池的容量是nThreads。已提交但是没有执行的任务,会被阻塞,直到有任务运行完成。

newFixedThreadPool()在调用ThreadPoolExecutor()时,会传递一个LinkedBlockingQueue()对象,而LinkedBlockingQueue单向链表实现的阻塞队列。在线程池中,就是通过该阻塞队列来实现"当线程池中任务数量超过允许的任务数量时,部分任务会阻塞等待"。

ThreadFactory

代码语言:javascript
复制
public static ThreadFactory defaultThreadFactory() {
    return new DefaultThreadFactory();
}
代码语言:javascript
复制
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;
    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }
    // 提供创建线程的API。
    public Thread newThread(Runnable r) {
        // 线程对应的任务是Runnable对象r
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        // 设为“非守护线程”
        if (t.isDaemon())
            t.setDaemon(false);
        // 将优先级设为“Thread.NORM_PRIORITY”
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

excute 添加任务到“线程池”

代码语言:javascript
复制
public void execute(Runnable command) {
    // 如果任务为null,则抛出异常。
    if (command == null)
        throw new NullPointerException();
    // 获取ctl对应的int值。该int值保存了"线程池中任务的数量"和"线程池状态"信息
    int c = ctl.get();
    // 当线程池中的任务数量 < "核心池大小"时,即线程池中少于corePoolSize个任务。
    // 则通过addWorker(command, true)新建一个线程,并将任务(command)添加到该线程中;然后,启动该线程从而执行任务。
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 当线程池中的任务数量 >= "核心池大小"时,
    // 而且,"线程池处于允许状态"时,则尝试将任务添加到阻塞队列中。
    if (isRunning(c) && workQueue.offer(command)) {
        // 再次确认“线程池状态”,若线程池异常终止了,则删除任务;然后通过reject()执行相应的拒绝策略的内容。
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 否则,如果"线程池中任务数量"为0,则通过addWorker(null, false)尝试新建一个线程,新建线程对应的任务为null。
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 通过addWorker(command, false)新建一个线程,并将任务(command)添加到该线程中;然后,启动该线程从而执行任务。
    // 如果addWorker(command, false)执行失败,则通过reject()执行相应的拒绝策略的内容。
    else if (!addWorker(command, false))
        reject(command);
}

shutdown 关闭线程池

代码语言:javascript
复制
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    // 获取锁
    mainLock.lock();
    try {
        // 检查终止线程池的“线程”是否有权限。
        checkShutdownAccess();
        // 设置线程池的状态为关闭状态。
        advanceRunState(SHUTDOWN);
        // 中断线程池中空闲的线程。
        interruptIdleWorkers();
        // 钩子函数,在ThreadPoolExecutor中没有任何动作。
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        // 释放锁
        mainLock.unlock();
    }
    // 尝试终止线程池
    tryTerminate();
}

线程池状态

  • Running
  • SHUTDOWN
  • STOP
  • TIDYING
  • TERMINATED
代码语言:javascript
复制
rivate final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

ctl是一个AtomicInteger类型的原子对象。ctl记录了"线程池中的任务数量"和"线程池状态"2个信息。 ctl共包括32位。其中,高3位表示"线程池状态",低29位表示"线程池中的任务数量"。

代码语言:javascript
复制
RUNNING    -- 对应的高3位值是111。
SHUTDOWN   -- 对应的高3位值是000。
STOP       -- 对应的高3位值是001。
TIDYING    -- 对应的高3位值是010。
TERMINATED -- 对应的高3位值是011。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.08.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 说明
  • 架构图
    • Executor 函数接口
      • ExecutorService
        • AbstractExecutorService
          • ThreadPoolExecutor
            • ScheduledExecutorService
              • ScheduledThreadPoolExecutor
                • Executors
                • 示例
                • 静态工厂类
                • ThreadFactory
                • excute 添加任务到“线程池”
                • shutdown 关闭线程池
                • 线程池状态
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档