线程池原理你知道多少?

程序员成长路上有着不同的阶段,只要你翻过了当时那个阶段,那么你将会有了不一样的收获。很多时候,我们在刚开始面对它们的时候,还看不清,看不透,云里雾里,让人觉得它们很高深。等我们正在的了解它们了之后就觉一切都是那么简单、自然。

 

再努力一下,一切将会不一样!—— 鲁迅

前言

多线程开发就是这样的一座山,需要我们去克服。说到多线程,大部分新手(作者自己),在面试中谈到多线程就慌了,因为自己在实际工作中真的很少碰到,而且我们多数时候都是在做传统的单体项目开发,说真的,很少会碰到用到多线程的,用都没用过面试的时候让我们怎么说。为了让大家对多线程有个大致了解,现在让作者我跟大家瞎扯几句,作者很少写文章,写得不太通顺的地方,大家多(wang)多(si)谅(li)解(pen) 。

 

既然要讲多线程,就不得不说下线程、线程池了~

 

 

线程

在Java中你会怎么创建一个线程吗?

很简单啊,比如说:

Thread t = new Thread(new Runnable() {
           @Override
           public void run() {
              // 处理逻辑代码
              process();
          }
      });
t.start();

恩,没错,这样确实可以简单的创建出一个线程对象。

我们知道一个线程的创建于销毁是需要消耗资源的,大家来思考一个问题:假设我们项目中要经常用到多个线程去处理业务的话,每次都是用完就销毁,这也未免太浪费了些吧,毕竟线程只是帮我们执行相应的任务,完全可以继续复用它呀,让它接着处理其他任务。那么在Java中有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?

如果之前大家有看过《阿里巴巴 Java 手册》的话,那么应该知道有那么一条:

可见线程池就是我们的答案!

线程池的作用

简单来说使用线程池有以下几个目的:

  • 线程是稀缺资源,不能频繁的创建。

  • 解耦作用,线程的创建于执行完全分开,方便维护。

  • 应当将其放入一个池子中,可以给其他任务进行复用。

线程池原理

简单来说就是把宝贵的资源管理起来,每次用的时候再去取,用完放回,让其他人也可以复用。

那在Java中我们该怎么实现呢?

在Java中线程池的核心类是ThreadPoolExecutor,并在此类的基础上封装了几种常用线程池:

  • Executors.newCachedThreadPool():无限线程池。

  • Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。

  • Executors.newSingleThreadExecutor():创建单个线程的线程池。

我们看下他们是怎么实现的:

// 无限线程池
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
   return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                 60L, TimeUnit.SECONDS,
                                 new SynchronousQueue<Runnable>(),
                                 threadFactory);
}
// 创建固定大小的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
       return new ThreadPoolExecutor(nThreads, nThreads,
                                     0L, TimeUnit.MILLISECONDS,
                                     new LinkedBlockingQueue<Runnable>());
}
// 创建单个线程的线程池
public static ExecutorService newSingleThreadExecutor() {
       return new FinalizableDelegatedExecutorService
          (new ThreadPoolExecutor(1, 1,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>()));
}

看上面源代码,我们知道它们都是基于ThreadPoolExecutor 实现的,那我们就来看看它们是给ThreadPoolExecutor传了什么参数才导致它们可以实现不同功能的线程池的呢?

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

由上面的参数解释,我们可以知道,线程池是通过设置corePoolSize(最小线程数)和maximumPoolSize(最大线程数)来确定线程池的大小范围,让线程池在我们定义范围内扩容、减容。线程池的扩容是要判断当前所需的线程数是否超过核心线程数阻塞队列也满了并且当前线程数小于最大线程数,都符合了,才会扩容。我们可以看下面的流程图来理解:

  • corePoolSize 核心线程数,为线程池的基本大小。

  • maximumPoolSize 为线程池最大线程大小。

  • keepAliveTimeunit 则是线程空闲后的存活时间。

  • workQueue 用于存放任务的阻塞队列。

  • threadFactory 线程工厂,主要用来创建线程。

  • handler 当队列和最大线程池都满了之后的饱和策略。

    • ThreadPoolExecutor.AbortPolicy 丢弃任务并抛出RejectedExecutionException异常

    • ThreadPoolExecutor.DiscardPolicy 也是丢弃任务,但是不抛出异常

    • ThreadPoolExecutor.DiscardOldestPolicy 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

    • ThreadPoolExecutor.CallerRunsPolicy 由调用线程处理该任务

 

 

虽然,Executors给我们封装好了上面几个构建线程池的方法,但是,并不建议直接使用

为什么呢?

让我们来看看阿里巴巴的开发手册:

让我们看下源码是不是真的这样:

  • Executors 源码

// Executors.class
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                      0L, TimeUnit.MILLISECONDS,
                      new LinkedBlockingQueue<Runnable>()));// 这里采用了无参构造方法
}
  • LinkedBlockingQueue源码

// LinkedBlockingQueue.class
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);  // 无参构造方法,直接设置为Integer.MAX_VALUE大小
}
public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
    last = head = new Node<E>(null);
}

果然如此~

所以还是按照我们自己业务上需求自定义配置属于自己的线程池吧!

好了,暂时先讲到这啦~

大家觉得不错帮忙点个在看哈~

 

参考:

https://blog.csdn.net/pange1991/article/details/53860651

《阿里巴巴Java开发手册》

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章