zoukankan      html  css  js  c++  java
  • 线程池

    线程池

    “线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。但是阿里的开发手册中不推荐使用Executors 来创建线程池

    阿里开发手册摘取内容如下:

    【强制】 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这
    样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
    说明: Executors 返回的线程池对象的弊端如下:
    	1) FixedThreadPool 和 SingleThreadPool:
    		允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM(内存溢出)。
    	2) CachedThreadPool:
    		允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM(内存溢出)。
    

    Executors 工具类

    常用方法(创建线程池的方法)

    返回值 方法名 说明
    ExecutorService newFixedThreadPool(int nThreads) 创建一个线程池对象, nThreads是线程池内的线程最大数量

    例如创建线程池: ExecutorService pool = Executors.newFixedThreadPool(3);

    实例代码:

    // 创建线程池对象 -- 参数是线程池的大小(线程数)
    ExecutorService pool = Executors.newFixedThreadPool(3);
    
    // 利用线程池执行线程任务
    // execute(); 参数需要Runnable接口类型
    for (int i = 0; i < 3; i++) {
        pool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                }
            }
        });
    }
    

    ThreadPoolExecutor创建线程池

    构造方法

    方法 说明
    ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue)
    corePoolSize 核心线程数
    maximumPoolSeze 最大线程数
    keepAliveTime 线程空闲多长时间被释放
    unit 时间单位
    wordQueue 任务队列
    ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory)
    与上面构造方法多了一个参数
    threadFactory线程工厂
    ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler)
    handler拒绝执行任务的一种策略
    ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler)
    包含了上面所有的参数

    其最大吞吐量为: 最大线程数 + 最大队列数

    代码案例-简单案例

    public static void main(String[] args) {
        // 任务队列. 这里设置为2
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        // 定义线程工厂, 可以自动以线程名字前缀
        ThreadFactory threadFactory = new ThreadFactory() {
            AtomicLong al = new AtomicLong(1); // 自动递增策略, 从1开始
            @Override
            public Thread newThread(Runnable r) {
                String name = "cgb2004-thread-" + al.getAndIncrement(); // 先获取值, 再自增
                return new Thread(r, name);
            }
        };
        ThreadPoolExecutor tExecutor = new ThreadPoolExecutor(
            2, // corePoolSize 核心线程数
            3, // maximumPoolSeze 最大线程数
            60, // keepAliveTime 线程空闲多长时间被释放
            TimeUnit.SECONDS, // unit 时间单位
            workQueue, // wordQueue 任务队列
            threadFactory, // threadFactory 线程工厂
            new CallerRunsPolicy()); // 拒绝执行任务的一种策略
    
        tExecutor.execute(new Runnable() { // 从线程池获取线程
            @Override
            public void run() {
                String tName = Thread.currentThread().getName();
                System.out.println(tName + "->task-01");
                // try{Thread.sleep(10000);} catch(Exception e) {}
            }
        });
        tExecutor.execute(new Runnable() { // 从线程池获取线程
            @Override
            public void run() {
                String tName = Thread.currentThread().getName();
                System.out.println(tName + "->task-02");
                // try{Thread.sleep(10000);} catch(Exception e) {}
            }
        });
        // tExecutor.execute(new Runnable()... 
    }
    

    执行流程描述

    首先, 核心线程数corePoolSize 即线程池中一直存在线程的数量, 当需要时会从里面取出线程使用

    当核心线程都在使用中, 那么就会加入到消息队列中如, 等核心线程空闲的时候, 队列中的任务才能执行

    当核心线程都在使用中, 且消息队列也达到了最大上限, 这时候又有任务来了, 那么就会创建新的线程, 来执行, 前提是线程池中的线程数量没有超过最大线程数

    如果说最大线程数也满了, 这时候又来了新的任务, 这时候会拒绝执行, 抛出异常, 当然, 我们也可以使用构造器中的RejectedExecutionHandler handler借口自定义拒绝执行的的策略, 例如传入一个new CallerRunsPolicy() 参数, 来让main线程执行等

  • 相关阅读:
    FastJson 配置Long转String类型 , 解决前后端交互, id过长,失去精度的问题
    idea使用技巧大全
    多线程下载工具
    https url 下载
    Jquery ajax请求格式
    AQS之可重入锁ReentrantLock原理
    整理所学之HashMap | 第二篇
    数据结构:哈希表例子
    整理所学之HashMap | 第一篇
    设计模式 | 第三篇:装饰者模式
  • 原文地址:https://www.cnblogs.com/zpKang/p/12983306.html
Copyright © 2011-2022 走看看