Java线程池学习笔记

Java线程池学习笔记

1.线程池

  1. 线程的创建和销毁需要一定的开销;
  2. 需要线程池对线程进行管理,减少资源的耗费;
  3. Executor框架将任务的创建和执行进行解耦:Runnable和Callable进行任务的创建,ThreadPoolExecutor用于执行任务;

1.1.Executor

execute和submit
  1. execute适用于"触发就忘"的场景,submit适合需要获取结果或控制任务状态的场景;
  2. submit的返回值是Future,可以通过Future检查任务是否完成,取消任务, 获取阻塞等待结果,执行到异常时不会立即抛出,在get方法会抛出异常

2.ThreadPoolExecutor

2.1.构造方法

java 复制代码
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  1. corePoolSize:核心线程数;调用prestartAllcoreThread会启动所有核心线程;

  2. maximumPoolSize:最大线程数;

  3. keepAliveTime:非核心线程超时回收时间;调用allowCoreThreadTimeout为true,超时回收也会应用到核心线程上;

  4. unit:上面参数的时间单位;

  5. workQueue:任务队列;

  6. threadFactory:线程工厂;作用:给创建的线程设置名字,代码:

    java 复制代码
     // 创建线程工厂,用于给线程命名
        ThreadFactory threadFactory = new ThreadFactory() {
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r, "MyThread-" + threadNumber.getAndIncrement());
                return t;
            }
        };
  7. RejectedExecutionHandler:饱和策略;当任务队列和线程数都满了时执行的策略,默认AbortPolicy:无法处理新任务,并抛出RejectedExecutionException异常;此外还有三种策略:

    1. CallerRunsPolicy:用调用者所在线程执行任务;
    2. DiscardPolicy:丢弃待执行的任务;
    3. DiscardOldestPolicy:丢弃队列中最早进入队列的任务(队列的头),执行当前任务

2.2.线程池执行顺序

  1. 启动核心线程
  2. 核心线程满了,加入任务队列
  3. 任务队列满了,启动非核心线程,数量不能超过最大线程数-核心线程数
  4. 执行饱和策略

3.线程池种类

3.1.Executors.newFixedThreadPool

  1. 实现:new ThreadPoolExecutor(n,n,0,TimeUnit.MILLISECONDS,new LinkedBlockingQueue())
  2. 工作流程:启动核心线程,核心线程满了加入任务队列,核心线程运行完取出任务执行
  3. 没有超时回收,因为没有非核心线程

3.2.Executors.newCachedThreadPool

  1. 实现:new ThreadPoolExecutor(0,Integer.MAX_VALUE,60,TimeUnit.SECONDS,new SynchronousQueue())
  2. 工作流程:加入任务队列,SynchronousQueue不支持存放元素,存储一个任务就需要移除它,所以要创建一个非核心线程取出任务进行执行,执行任务时如果有空闲线程就不创建新线程,反之需要创建
  3. 线程执行完任务空闲60s没有任务过来超时回收

3.3.Executors.newSingleThreadExecutor

  1. 实现:new ThreadPoolExecutor(1,1,0,TimeUnit.MILLISECONDS,new LinkedBlocking())
  2. 工作流程:创建核心线程,添加到任务队列,取出任务队列执行
  3. 特点:单个线程按顺序执行任务

3.4.Executors.newScheduledThreadPool

  1. 实现:new ThreadPoolExecutor(n,Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLISSECONDS,TimeUnit.MILLISECONDS,new DelayedWorkQueue())

  2. 工作流程:创建核心线程,放入队列等待核心线程空闲,因为DelayedWorkQueue无界,基本不会创建非核心线程

  3. 常用API:

    • schedule:延时执行
    java 复制代码
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    
    // 场景1:3秒后发送一条通知
    scheduler.schedule(() -> {
        System.out.println("3秒到了,发送推送通知");
    }, 3, TimeUnit.SECONDS);
    • scheduleAtFixedRate:固定频率执行
    java 复制代码
    // 场景2:每5秒检查一次网络状态(不管任务执行多久)
    scheduler.scheduleAtFixedRate(() -> {
       System.out.println("检查网络连接状态...");
       // 假设这个检查需要2秒
    }, 0, 5, TimeUnit.SECONDS);
    // 参数:首次延迟0秒,之后每5秒执行一次
    • scheduleWithFixedDelay:固定延迟执行
    java 复制代码
    	// 场景3:每次请求完成后,等待3秒再进行下一次
    scheduler.scheduleWithFixedDelay(() -> {
        System.out.println("拉取服务器数据...");
        // 假设拉取数据需要2秒
        Thread.sleep(2000);
    }, 0, 3, TimeUnit.SECONDS);
    // 执行流程:拉取(2秒) -> 等待3秒 -> 拉取(2秒) -> 等待3秒...

4.线程池和其他API比较

4.1.Android开发很少用Executors的原因

  1. 生命周期管理复杂

    java 复制代码
    // 容易忘记shutdown,导致内存泄漏
    // 需要在每个Activity的onDestroy中处理,容易遗漏
  2. 有更好的替代方案
    替代方案 优势
    Kotlin Coroutines 自动绑定生命周期,Scope管理
    RxJava 丰富的操作符,自动取消订阅
    WorkManager 系统级任务调度,保证执行
    LiveData + Room 数据库异步查询自动管理

相关推荐
C羊驼1 小时前
C语言学习笔记(十二):动态内存管理
c语言·开发语言·经验分享·笔记·青少年编程
hongtianzai2 小时前
Laravel8.x核心特性全解析
java·c语言·开发语言·golang·php
逸Y 仙X2 小时前
文章十一:ElasticSearch Dynamic Template详解
java·大数据·数据库·elasticsearch·搜索引擎·全文检索
我不是程序猿儿2 小时前
【嵌入式】编码器计数倍频,机械一格与电气计数
stm32·单片机·嵌入式硬件·学习
隔壁小邓2 小时前
IDEA 中同时启动多个微服务
java·微服务·intellij-idea
:1212 小时前
idea17创建tomcat项目(计网底层核心理解!)
java·ide·intellij-idea
阳光永恒7362 小时前
C++编程全套学习资料免费分享 | 从零基础到进阶(含视频课/PPT课件/源码/项目实战)
c++·学习·编程学习·免费资料·零基础学c++·c++资料
Дерек的学习记录2 小时前
Unreal Engine 5:前置知识和入门基础
学习·ue5
笑鸿的学习笔记2 小时前
Windows笔记之windows11和windows10启动速度优化
windows·笔记