本节要点

  • 学会多线程的应用场景
  • 多线程实现的方式
  • 学会如何使用线程池
  • 学会再SpringBoot里怎么使用多线程

1、什么是多线程

[明白单线程]

单线程是指一个程序(进程)从头到尾只有一条唯一的执行路径。这条路径被称为主线程(Main Thread)

image-20260109095301737

你可以把它想象成一条单车道:所有的车辆(任务)都必须在这条车道上排成一队,顺序通过。前一辆车不开走,后一辆就只能等着

image-20250822100628403

多线程(Multithreading) 就是指一个进程同时运行多个线程来完成不同的任务。

image-20260109095246867

image-20250822100642186

2、什么场景用多线程?

  • “打造灵敏的用户界面”

    为了防止主线程阻塞,并行执行多个任务,相互不影响

  • cpu资源足够的情况下,有效利用cpu资源,多并发处理业务

    image-20260121173046928

3、如何使用多线程

1. 继承 Thread 类

这是最基本的方法,通过继承 Thread 类并重写 run() 方法。

class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的代码
        System.out.println("线程运行: " + Thread.currentThread().getName());
    }
}
...
xxx.start();

2. 实现 Runnable 接口

lass MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行的代码
        System.out.println("Runnable运行: " + Thread.currentThread().getName());
    }
}

线程资源建议通过线程池创建,尽量不要在应用中自行显式创建线程。

3.使用线程池

  • Executors (不建议使用)
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);


// 提交任务
fixedThreadPool.submit(() -> {
    // 你的任务代码
    System.out.println("Task executed by " + Thread.currentThread().getName());
});

// 关闭线程池
fixedThreadPool.shutdown();
  • ThreadPoolExecutor(建议使用)

线程池不要使用 Executors 去创建,用 ThreadPoolExecutor 的方式。

4、ThreadPoolExecutor参数

ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 
                //核心线程数
                corePoolSize:10, 
                //临时线程数
                maximumPoolSize:20, 
                //临时线程超时时间 
                keepAliveTime:60L, 
                TimeUnit.SECONDS, 
                //任务队列
                new ArrayBlockingQueue<Runnable>(capacity:10), 
                //创建线程的工厂
                Executors.defaultThreadFactory(), 
                //拒绝策略
                new ThreadPoolExecutor.AbortPolicy() 
        ); 

5、ThreadPoolExecutor原理

image-20260109104656018

  • 有界队列

    说明:

    核心线程 -> 放队列->开临时线程 ->拒绝策略

    new ArrayBlockingQueue<Runnable>(capacity:10),
    
  • 无界队列

    说明:永远不会创建超过核心线程数的线程,因为队列永远不会满。

    核心线程 ->放队列->等oom

     new LinkedBlockingQueue<>()  
    
  • 同步移交

    说明:不会放到队列里面

    核心线程->开临时线程->拒绝策略

    new SynchronousQueue<>() 
    

6、拒绝策略

1. AbortPolicy(中止策略)

  • 含义默认策略。直接抛出 RejectedExecutionException 异常,阻止系统正常运行
  • 特点:最严格的策略,确保任务不会丢失,但需要调用者处理异常
  • 适用场景:关键任务系统,不能容忍任务丢失的情况

2. CallerRunsPolicy(调用者运行策略)

  • 含义:将任务回退给调用者线程执行(即提交任务的线程自己执行)
  • 特点:不会丢弃任务,但会降低新任务提交速度,起到简单的反馈调节作用
  • 适用场景:需要保证所有任务都能被执行,且可以接受提交速度变慢的场景

3. DiscardPolicy(丢弃策略)

  • 含义静默丢弃无法处理的任务,不抛异常,也不做任何通知
  • 特点:最简单粗暴的策略,可能造成任务丢失而不自知
  • 适用场景:无关紧要的任务,允许丢弃一些请求的场景

4. DiscardOldestPolicy(丢弃最老策略)

  • 含义:丢弃队列中最老的(最先进入队列的)任务,然后尝试重新提交当前任务
  • 特点:用新任务替换旧任务,可能丢失重要但排队久的任务
  • 适用场景:新任务比旧任务更重要的场景,如实时性要求高的系统

4、如何使用

package com.daiwei.springmvc.uti;

import java.util.concurrent.*;

public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        ThreadPoolExecutor executor1 = new ThreadPoolExecutor(5,
                10,
                6000,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        executor1.execute(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程");
        });
        System.out.println("主线程");
    }
}

spring mvc里使用

1、加一个配置(纳入spring容器管理)

package com.daiwei.springmvc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;

@Configuration
public class ThreadPoolConfig {

    @Bean("customThreadPool1")
    public ThreadPoolExecutor customThreadPool() {
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        int maxPoolSize = corePoolSize * 2;
        int queueCapacity = 100;

        return new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
    @Bean("customThreadPool2")
    public ThreadPoolExecutor customThreadPool() {
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        int maxPoolSize = corePoolSize * 2;
        int queueCapacity = 100;

        return new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
}

serviceImpl里注入

    ...
    @Autowired
    ThreadPoolExecutor threadPoolExecutor;

    @RequestMapping("/register")
    public String register(@RequestParam("name") String name, @RequestParam("pwd") String pwd) {
        ...
        threadPoolExecutor.execute(()->{
            System.out.println("==============hello="+name+"==pwd="+pwd);
        });
        ...
        return "success";
    }

spring Config加入加入整个配置

package com.daiwei.springmvc.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.sql.DataSource;

@Configuration
@ComponentScan({"com.daiwei.springmvc.service","com.daiwei.springmvc.dao"})
@Import({MybatisConfig.class,JdbcConfig.class,ThreadPoolConfig.class})//@Import 注解会将指定的类注册到IOC中
@EnableAspectJAutoProxy
public class SpringConfig implements WebMvcConfigurer {


}

6、spring boot里如何使用

ThreadPoolTaskExecutor
  • 增加一个配置类
@Configuration
@EnableAsync
public class ThreadPoolConfig {
    @Bean("threadPoolTaskExecutor1")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数
        executor.setCorePoolSize(5);
        //最大线程数
        executor.setMaxPoolSize(10);
        //线程池所使用的缓冲队列
        executor.setQueueCapacity(100);
        //等待时间超过60秒后线程将被回收
        executor.setKeepAliveSeconds(60);
        //线程拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.initialize();
        return executor;
    }
  
    @Bean("threadPoolTaskExecutor2")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数
        executor.setCorePoolSize(5);
        //最大线程数
        executor.setMaxPoolSize(10);
        //线程池所使用的缓冲队列
        executor.setQueueCapacity(100);
        //等待时间超过60秒后线程将被回收
        executor.setKeepAliveSeconds(60);
        //线程拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.initialize();
        return executor;
    }
}
  • service 加上注解

    @Async("threadPoolTaskExecutor1")
    
    @Async("threadPoolTaskExecutor2")