博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JUC - 线程池:
阅读量:3920 次
发布时间:2019-05-23

本文共 5188 字,大约阅读时间需要 17 分钟。

线程池:

在这里插入图片描述

  1. 为什么使用线程池:(在之前已经是使用过三种创建多线程的方式 那么为什么还要有线程池的方式 一个新技术的出现一定是有它的独到之处 )

    • 线程池的优势:

      • 线程池的优势:线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
    • 线程池的主要特点:

      • 线程复用 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗
      • 控制最大并发数 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行
      • 管理线程 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
    • 线程池的继承关系:Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类

      在这里插入图片描述

  2. 使用JDK自带的线程池:使用的类 Executors工具类 但是底层上实际是new ThreadPoolExecutor()

    • 创建一个:有固定线程数的线程池:newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue

      在这里插入图片描述

    • 创建一个线程池中只能有一个线程的线程池:newSingleThreadExecutor 创建的线程池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue

      在这里插入图片描述

    • 创建一个可扩容的线程池:newCachedThreadPool创建的线程池将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程

      在这里插入图片描述

    • 虽然是在JDk中的线程池 但是ali开发手册中却是不推荐使用:

      • 前两种线程池使用的是LinkedBlockingQueue 默认创建是Integer.MAX_VALUE个元素 也就是最多能阻塞21亿多个线程 这样就会造成OOM
        在这里插入图片描述
      • 第三种可扩容的最大可扩容的就是21亿个线程 也是同样会造成OOM
  3. 上面的线程池底层都是使用的是ThreadPoolExecutor 这里就详细解释一下:

    • 构造函数:构造函数又非常多种 这一种是最基本的 也就是7个参数的

      public ThreadPoolExecutor(int corePoolSize,  // 线程池中常驻的核心线程数                           int maximumPoolSize,  // 线程池中能容纳同时执行的最大线程数 此值必须大于等于1                          long keepAliveTime,  // 多余的空闲线程的存活时间                          TimeUnit unit,  // 时间单位                          BlockingQueue
      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.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler;}
    • 参数的说明:

      • 拒绝策略:
        • AbortPolicy 丢弃任务并抛出RejectedExecutionException异常 这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态 如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现
          在这里插入图片描述
        • CallerRunsPolicy调用线程处理该任务 从哪来回哪去 这里就是main线程去处理
          在这里插入图片描述
        • DiscardOldestPolicy 丢弃队列最前面的任务,然后重新提交被拒绝的任务。
        • DiscardPolicy 和第一种一样 也是丢弃任务 但是不抛出异常 如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃
      • 线程池中能容纳的最大线程数:maximumPoolSize + 任务队列的容量
    • 自定义线程池的使用:

      package com.interview.concurrent.threadpool;import java.util.concurrent.*;public class ThreadPoolExecutorDemo {
      public static void main(String[] args) {
      threadPoolExecutor(); } public static void threadPoolExecutor(){
      ExecutorService threadPool = new ThreadPoolExecutor( 2, // 核心池子的大小 5, // 线程池最大大小5 2L, // 空闲线程的保留时间 TimeUnit.SECONDS, // 超时回收空闲的线程 new LinkedBlockingDeque<>(3), // 根据业务设置队列大小,队列大小一定要设置 原因上面说过了 Executors.defaultThreadFactory(), // 不用变 一般使用默认的 new ThreadPoolExecutor.CallerRunsPolicy() //拒绝策略 看这样的创建方式就知道拒绝策略是 ThreadPoolExecutor的静态内部类 ); try {
      // 队列 RejectedExecutionException 拒绝策略 for (int i = 1; i <= 10; i++) {
      // 默认在处理 threadPool.execute(()->{
      System.out.println(Thread.currentThread().getName()+" running...."); }); } } catch (Exception e) {
      e.printStackTrace(); } finally {
      threadPool.shutdown(); } }}
  4. 线程池处理流程:非常重要 (常见的面试题)在这里插入图片描述

    • 处理流程的详解:
      • 在创建了线程池后,线程池中的线程数为零

      • 当调用execute()方法添加一个请求任务时,线程池会做出如下判断:

        • 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务
        • 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列
        • 如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
        • 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行
      • 当一个线程完成任务时,它会从队列中取下一个任务来执行

      • 当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断:如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉 线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

        public void execute(Runnable command) {
        if (command == null) throw new NullPointerException(); int c = ctl.get(); // ctl 是一个原子整型 //addWorker 才是创建线程的方法 也就是任务提交的时候才创建线程 if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true)) return; c = ctl.get(); } // 不是直接创建非核心线程 而是先放在workQueue中 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); } else if (!addWorker(command, false)) reject(command); }
  5. 线程池中最大线程数如何配置:

    • CPU 密集型:最大支持多少个线程同时跑,根据CPU去设置,一般设置成与CPU处理器一样大,每一次都要去写吗? 通过Runtime来获取

      Runtime.getRuntime.availableProcessors();// 获取当前的可用核数
    • IO 密集型:磁盘读写、 一个线程在IO操作的时候、另外一个线程在CPU中跑,造成CPU空闲。最大线程数应该设置为 IO任务数! 对于大文件的读写非常耗时,我们应该用单独的线程让他慢慢跑

转载地址:http://lfxrn.baihongyu.com/

你可能感兴趣的文章
Educational Codeforces Round 85 (Rated for Div. 2)B. Middle Class
查看>>
Educational Codeforces Round 86 (Rated for Div. 2)---题解(A、B、C)
查看>>
Educational Codeforces Round 87 (Rated for Div. 2)----题目+题解(A、B)
查看>>
Educational Codeforces Round 88 (Rated for Div. 2)A. Berland Poker------题目+题解
查看>>
Educational Codeforces Round 88 (Rated for Div. 2)B. New Theatre Square-------题目+题解
查看>>
Educational Codeforces Round 88 (Rated for Div. 2)C. Mixing Water(数学+二分法)---题解
查看>>
Codeforces Round #646 (Div. 2)B.Subsequence Hate(贪心)---题目+题解
查看>>
Codeforces Round #647 (Div. 2) - Thanks, Algo Muse!A. Johnny and Ancient Computer(数学)---题解
查看>>
Codeforces Round #647 (Div. 2) - Thanks, Algo Muse!B. Johnny and His Hobbies(异或)---题解
查看>>
Codeforces Round #647 (Div. 2) - Thanks, Algo Muse!C. Johnny and Another Rating Drop(找规律)---题解
查看>>
一文掌握JavaBean技术__JavaWeb
查看>>
洛谷P1271 【深基9.例1】选举学生会_C++描述
查看>>
操作INI文件的读写类
查看>>
vs2012编译的程序在XP下运行提示无法定位输入点XXXXX到kernel32.dll
查看>>
vs2012 编译jsoncpp和使用jsoncpp lib出现的问题
查看>>
关于jsoncpp内部排序的问题
查看>>
VC编译选项/MT/MTd/MD/MDd说明
查看>>
使用WinINet获取网页源代码
查看>>
VS提示内存泄漏(Detected memory leaks)的解决方法
查看>>
json_value.asm: No such file or directory
查看>>