java线程池(简单易懂)

 1 .线程池主要核心原理和优势

   1.1线程池核心原理

  1. 创建一个池子,池子当中是空的
  2. 提交任务时,池子会创建新的线程对象,任务执行完毕,线程会归还给池子,下次再次提交任务时,不需要创建新的线程,直接复用已有的线程即可。
  3. 如果提交任务时,池子中没有空闲线程,也无法创建新的线程,队伍就会排队等待。

 1.2线程池主要优势

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

2. 线程池的代码实现

2.1通过Executors线程池工具类通过调用方法创建不同类型的线程池对象。

//代码实现
     /**
     * 创建一个没有上限的线程池
     */
      ExecutorService executorService = Executors.newCachedThreadPool();
        /**
         * 往线程池中提交任务
         */
        LoopTread loopTread = new LoopTread();
        executorService.submit(loopTread);
        executorService.submit(loopTread);
        executorService.submit(loopTread);
        executorService.submit(loopTread);

    /**
     * 销毁线程池
     * 此方法一般不用,因为线程池一般在项目中不进行销毁,随时会有任务
     */
        executorService.shutdown();



    /**
     * 创建一个有上限的线程池
     * 3代表这个线程最多只能同时有三个线程
     */
    ExecutorService executorService1 = Executors.newFixedThreadPool(3);
    /**
     * 提交任务
     * 提交五个任务,从控制台输出可以看出线程的复用
     */
    executorService1.submit(loopTread);
    executorService1.submit(loopTread);
    executorService1.submit(loopTread);
    executorService1.submit(loopTread);
    executorService1.submit(loopTread);

 一共五个任务,但确只使用了三个线程,这就是线程池里的代码复用。

java线程池(简单易懂)_第1张图片

2.2自定义创建线程池(创建ThreadPoolExecutor类)

它最长的构造方法有七个参数。

  1. 核心线程数量——在线程池当中无论空闲多久都不会被删除的线程
  2. 线程池当中最大的线程数量——线程池当中最大能创建的线程数量
  3. 空闲时间(数值)——临时线程(线程池中出核心线程之外的线程)空闲了多久就会被淘汰的时间。
  4. 空闲时间(单位)——临时线程空闲了多久就会被淘汰的时间单位,要用枚举类TimeUnit类作为参数
  5. 阻塞队列——就是创建一个阻塞队列作为参数传入,就是当线程池当中线程数量已经达到了最大线程数量,允许多少个任务排队获取线程,其余的用参数七那个方案来处理。
  6. 创建线程的方式——不是new一个线程,而是传入一个线程工厂(例如:Executors工具类中的defaultThreadFactory方法返回的就是一个线程工厂)
  7. 要执行的任务过多时的解决方案——当等待队列中也排满时要怎么处理这些任务(任务拒绝策略)。

java线程池(简单易懂)_第2张图片

//代码实现
   /**
     * 之前用工具类进行创建,有好多参数不能自己设置
     * 咱直接自己手动创建一个线程池,自己设置参数
     * 参数一:核心线程数量                           不能小于0
     * 参数二:最大线程数                             不能小于0,数值大于等于核心线程数量
     * 参数三:空闲临时线程最大存活时间(数值)           不能小于0
     * 参数四:空闲临时线程最大存活时间(单位)            用TimeUnit这个枚举类表示
     * 参数五:任务队列,也就是一个堵塞队列               不能为null
     * 参数六:创建线程的工厂                            不能为null
     * 参数七:任务的拒绝策略                             不能为null
     */
 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        3,  // 核心线程数量
        6,              //最大线程数
        60,             //空闲临时线程最大存活时间(数值)
        TimeUnit.SECONDS,//空闲临时线程最大存活时间(单位)
        new ArrayBlockingQueue<>(3),//任务队列,也就是一个堵塞队列,也可以使用LinkedBlockingQueue这个阻塞队列
        Executors.defaultThreadFactory(),//用线程池工具类Executors创建线程的工厂
        new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略中其中一个,丢弃任务并抛出RejectedExecutionException
    );
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    threadPoolExecutor.submit(loopTread);
    }

上面的代码我们设置最大线程数量为6,而阻塞队列可以排三个,说明当同时有超过9个任务需要执行,第10个线程就会执行拒绝策略,我设置的策略为丢弃任务,并抛出异常RejectedExecutionException。下面有结果就可以证明我们的猜测。

 74行恰好是我们放入线程池中第10个任务,所以第74行抛出了RejectedExecutionException异常。java线程池(简单易懂)_第3张图片

自定义线程在不断的提交任务时有三个临界点:

  • 当核心线程满时,再提交队伍就会在阻塞队列中排队
  • 当核心线程满了,阻塞队列中也满了,才会创建临时线程
  • 当核心线程满了,阻塞队列满了,临时线程也满了,会触发任务拒绝策略,也就是参数七

你可能感兴趣的:(java,开发语言)