Blage's Coding Blage's Coding
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
  • JAVA基础

  • 集合容器

  • Netty

  • JVM

  • JUC

    • 并发机制初识
    • JMM语义与重排
    • 多线程通信与编程应用
    • Lock并发锁原理
    • 并发容器与框架
    • 原子操作类
    • 并发工具类
    • 线程池
    • Executor框架
      • 1.Executor框架简介
      • 2.ThreadPoolExecutor
        • FixedThreadPool:
        • SingleThreadExecutor
        • CachedThreadPool
      • 3.ScheduledThreadPoolExecutor
      • 4.FutureTask
        • API用例
        • 源码解析
        • get()方法
        • run()方法
    • 并发编程实践
    • JUC面试
  • Java
  • JUC
phan
2023-10-19
目录

Executor框架

# Executor框架

Java中将任务和调度分开。任务单元为Runnbale,而执行机制和任务调度由Executor框架提供。

在JVM线程模型中,java.lang.Thread与系统线程是一一对应的。Executor负责若干个任务映射成对应的Java线程,操作系统底层再调度系统线程。

# 1.Executor框架简介

框架主要包含三个部分:

  • Runnable接口不会返回结果,而Callable可以返回结果。
  • Executor接口创建线程执行任务。
  • Future接口用于获取异步计算的结果。FutureTask实现类。

Executors是工厂类,用于创建两种类型的线程池:

# 2.ThreadPoolExecutor

下面介绍如下三种线程池:

# FixedThreadPool:

  • 线程数量:核心线程数、最大线程数都设置为固定值。
  • 任务队列:使用无界队列,不存在拒绝任务的情况。存在任务过多内存移除的风险。

# SingleThreadExecutor

  • 线程数量:核心线程数、最大线程数都设置为1.
  • 任务队列:使用无界队列。反复从任务队列取出并执行,因此任务执行是有序的。

# CachedThreadPool

线程队列执行poll将空闲线程出队,如果60s内没有任务offer进来,那么该线程直接终止。

  • 线程数量:核心线程数为0,最大线程数为MAX_VALUE。
  • 任务队列:使用无容量的SynchronousQueue。必须等队列中的添加元素被消费后才能继续添加新的元素,否则会被阻塞。
  • 适用于执行大量短期异步任务

# 3.ScheduledThreadPoolExecutor

可以延期执行任务,适用于多个后台线程执行周期任务。

每个任务对象ScheduledFutureTask主要几个成员变量:

  • time:开始执行时刻
  • period:任务执行的周期(过了多久要执行下一次)

任务队列使用DelayQueue,会根据任务的开始执行时刻进行优先级排序:

  • 取出最早time的任务,并执行
  • 修改time为下次执行的时间currentTime+period
  • 放回任务队列中

# 4.FutureTask

注意:本身FutureTask并不是一个线程,需要启动一个新的线程执行。在另一个调用get()的线程才能被阻塞。

# API用例

FutureTask提供了以下异步任务方法和API:

  • FutureTask本身实现了Runnable接口,因此可以执行run方法执行任务。
  • get()方法会阻塞“调用线程”,知道任务执行结束并返回结果。
  • cancel()方法会导致任务永远不会被执行。

使用时创建FutureTask任务,并交给线程池或创建一个新线程来执行。通过get()方法阻塞当前线程获取结果。

FutureTask<Integer> future = new FutureTask<Integer>(new Job(20));
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(future);
Integer integer = future.get();
1
2
3
4

# 源码解析

内部是通过AQS实现一个同步类Sync,通过sync来控制执行状态。

# get()方法

通过awaitDone()方法阻塞线程:

  • 自旋判断当前任务执行状态state,若执行完毕则直接返回结果。否则按序执行如下步骤:

  • CAS向等待队列加入当前get调用的线程(创建WaitNode节点),存在多个线程都调用get阻塞的情况。

  • LockSupport.part阻塞当前线程

# run()方法

执行完任务后,CAS修改线程状态,并最后通过finishCompletion()方法唤醒等待队列的线程:

  • CAS获取waiters等待队列,并置为空。(实际上这里不需要多线程控制)
  • 依次取出每个等待队列节点,并执行LockSupport.unpark唤醒线程。
编辑 (opens new window)
#JUC
上次更新: 2023/12/15, 15:49:57
线程池
并发编程实践

← 线程池 并发编程实践→

Theme by Vdoing | Copyright © 2023-2024 blageCoder
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式