一万小时学编程:Java线程池原理

一万小时学编程系列

《一万小时定律》格拉德威尔:“人们眼中的天才之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成世界级大师的必要条件。”



前言

线程池是学习Java的重点也是难点,在面试中也会经常问到,尤其是对“高并发”有较高要求的企业,所以学好线程池原理很重要,本文是我参考大佬的博客写的,后边有链接地址。闲话不多说,让我们开始学习吧。


一、并发队列

1.概念

并发队列是一个基于链接点的无界线程安全队列,它采用先进先出的规则对节点进行排序,添加元素是在队列尾部,获取返回队列头部元素。

2.分类

并发队列分为阻塞队列和非阻塞队列,下面举例说明两者的区别。
非阻塞队列:入队操作,如果容器满了则会丢失。出队操作如果容器空返回null。
阻塞队列:入队操作,如果容器满了则会等待,有出队操作之后再入队。出队操作时如果容器空了则会等待,有入队操作之后再出队。
在这里插入图片描述
线程池就是基于阻塞队列实现。


二、线程池简介

多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:

  1. 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
  2. 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
  3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
  4. 任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

三、线程池原理

1.ThreadPoolExecutor核心类

线程池最上层接口是Executor,这个接口定义了一个核心方法execute(Runnablecommand),该方法是用来传入任务的,最后被ThreadPoolExecutor类实现。ThreadPoolExecutor是线程池核心类,构造方法如下:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue);

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

各个参数表示意义:

参数名参数含义
corePoolSize核心线程池大小,也即核心线程的数量
maximumPoolSize最大线程池大小,也即线程的最大数量
keepAliveTime空闲时间,是除核心线程之外的新创建线程的最大存活时间
TimeUnit时间单位
workQueue阻塞队列,用来存储等待的任务
threadFactory线程工厂,用来创建新线程
handler拒绝处理策略,当提交给线程池的任务量超过最大线程池大小+队列长度,就会采取拒绝处理策略

2.线程池原理图

在这里插入图片描述

过程描述如下:用户提交任务,线程池开始工作,当任务数小于核心线程数时,任务直接分配给核心线程执行。当任务数比核心线程数大时,这时所有核心线程都已分配任务,未分配完的储存在任务队列中,当核心线程完成之后执行。如果队列满了还有源源不断的任务到来,此时线程池会创建新线程开始执行任务,此时核心线程和新线程开始执行任务,如果,还是有任务提交,核心线程和新线程都在执行,队列都满了,那么此时线程池会报错拒绝任务,等到队列有空位时再接受任务。同样当任务数量减少,队列优先将任务交给核心队列处理,当新线程没有任务处理时就会自动关闭。值得注意的是这是一个动态的过程,其实还是蛮好理解的,

3.线程池实例

通过一个例子来了解线程池的基本原理。

public class Test{
       public static void main(String[] args){
               ThreadPoolExecutor pool=new ThreadPoolExecutor(1,2,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(3)); 
               for(int i=0;i<7;i++){
                     pool.execute(new TestThread());
               }
               pool.shutdown();               
       }
}
class TestThread implements Runnable{
      @Override
      public void run(){
             System.out.println(Thread.currentThread().getName());
      }
}

构造函数:ThreadPoolExecutor(1,2,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(3))中五个参数的含义。

  1. 1:核心线程数为1
  2. 2:最大线程数为2,所以可以新建一个线程
  3. 3:空闲时间,新建线程执行任务后等待新任务的空闲时间
  4. TimeUnit.SECONDS:时间单位,秒
  5. new LinkedBlockingDeque<>(3):阻塞队列,长度为3

运行结果:执行到第6条时开始报错。线程池拒绝新任务

在这里插入图片描述


总结

>以上就是今天要讲的内容,本文仅仅简单介绍了线程池的原理,而线程池更深刻的含义等待大家去挖掘,多读源码,多看帖子是最有效的提升之道。本文是参考大佬的博客写的,有不足的地方欢迎指正,如果本文对你有所帮助的话请关注点赞,你的鼓励是我最大的动力。
@我在风花雪月里等你:JAVA-线程池的基本原理https://blog.csdn.net/wei_zhi/article/details/52767651

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值