线程池源码浅析

基本概念

简单理解,线程池实际上就是一个线程可以复用的队列

线程池执行的了流程

 

执行方法核心源码分析:

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(null, false);
    }
    //如果放入workQueue任务失败,则创建线程任务,如果创建线程任务失败,就会调用reject
    else if (!addWorker(command, false))
        reject(command);
}

Executors创建线程池的方法:

1、newSingleThreadExecutor

创建一个单线程的线程池,只会有一个线程来执行任务,保证所有任务按照指定顺序执行

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

2、newFixedThreadPool

创建拥有固定线程数的线程池,控制线程最大并发超出的线程会在队列中等待

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

3、newCachedThreadPool

创建一个可缓存线程池,每个线程创建之后都有一定的存活期,如果在存活期间没有需要处理的线程则进行回收,若无可回收,则新建线程。

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

4、newScheduledThreadPool

创建一个固定线程数的线程池,支持定时及周期性任务执行

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

线程池的构造方法

public ThreadPoolExecutor(int corePoolSize,//指定了线程池中的线程数量
                          int maximumPoolSize,//指定线程池中最大线程数
                          long keepAliveTime,//当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多次时间内会被销毁
                          TimeUnit unit,//keepAliveTime 的单位
                          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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

常问面试题

1.为什么使用线程池?

答:线程的创建和销毁的花销都是比较大的,这些时间有可能比业务处理时间更长。线程池的复用将创建和销毁的步骤省去了。

2.线程池的作用?

答:1.效率高(省去了创建销毁的过程);2.方便管理。

3.线程池有哪几种工作队列?

答:

  1. ArrayBlockingQueue: 数组结构的有界阻塞队列,先进先出
  2. LinkedBlockingQueue:链表结构的阻塞队列,先进先出
  3. SynchronousQueue:不存储元素的阻塞队列
  4. PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

4.阻塞和非阻塞队列的区别?

阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值