Java 线程池-不会吧!有人不会线程池?看完这篇直接上手线程池!

什么是线程

线程是操作系统中最小的单位。

详解: 进程大家应该略有耳闻吧,进程由n个线程组成,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

什么是线程池

线程池是一种线程使用的模式,线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。

详解:线程池相当于一个租车公司,租车公司有固定的车辆(假设30辆),每辆车相当于一个线程,被租出去则是运行中,空着这是闲置中。

线程池常见类别

  1. newCachedThreadPool
  2. newFixedThreadPool
  3. newSingleThreadExecutor
  4. newScheduleThreadPool
  5. newSingleThreadScheduledExecutor

不同的线程池有对应的区别,想详细了解的cxy可以正对性的去学习,本文讲以上解线程池内部都会实现的ThreadPoolExecutor方法,已ThreadPoolTaskExecutor为例。

代码

pom.xml

<!--配置文件加载-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--这边里只给出特别需要的dependency,启动类的基本dependency 就不展示了-->

application.yml

async:
  corePoolSize: 3
  maxPoolSize: 4
  queueCapacity: 1
  namePrefix: async-newThreadName-
server:
  port: 8088

配置类(Config)

package com.example.qrcode.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * @author lyj
 * @version 1.0
 * @date 2021/1/26 14:19
 */
@Configuration
@EnableAsync
@ConfigurationProperties(prefix = "async")
@Data
public class ExecutorConfig {
    private int corePoolSize; //线程池的基本数量
    private int maxPoolSize; //线程池维护线程的最大数量(最大数量>=基本数量)
    private int queueCapacity; //线程池所使用的缓冲队列(顾名思义等待列队,当全部线程处于运行中时,还有新任务就进列队排队)
    private String namePrefix; //线程名字前缀(只是线程名字)
     @Bean(name = "asyncServiceExecutor")
     public Executor asyncServiceExecutor() {
            System.err.println("初始化线程池-----");
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //配置核心线程数
            executor.setCorePoolSize(corePoolSize);
            //配置最大线程数
            executor.setMaxPoolSize(maxPoolSize);
            //配置队列大小
            executor.setQueueCapacity(queueCapacity);
            //配置线程池中的线程的名称前缀
            executor.setThreadNamePrefix(namePrefix);
            // rejection-policy:当pool已经达到max size的时候,如何处理新任务
            // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            //执行初始化
            executor.initialize();
            return executor;
        }
}

实现类(Controller)

package com.example.qrcode.utile;
import com.example.qrcode.config.ExecutorConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Executor;
/**
 * @author lyj
 * @version 1.0
 * @date 2021/1/26 14:06
 */
@RestController
public class AsyncTask {
    @Autowired
    private Executor asyncServiceExecutor;
    
    private final Integer totalRunNum=20; //运行次数
    
    @RequestMapping(value = "index")
    public String index(){
        asyncServiceExecutor.execute(
        
        //一个线程的开始
        asyncServiceExecutor.execute(
        new TimerTask() {
            @Override
            public void run() {
                String name=Thread.currentThread().getName();
                for (int i = 1; i <= totalRunNum; i++) {
                    System.out.println(name+":第"+i+"次测试");
                    if (i == totalRunNum){
                        System.out.println(name+"结束。");
                    }
                    try {
                        Thread.currentThread().sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
              }
          }
      );
      //一个线程的结束      
      asyncServiceExecutor.execute(
              new TimerTask() {
                  @Override
                  public void run() {
                      String name=Thread.currentThread().getName();
                      for (int i = 1; i <= totalRunNum; i++) {
                          System.out.println(name+":第"+i+"次测试");
                          if (i == totalRunNum){
                              System.out.println(name+"结束。");
                          }
                          try {
                              Thread.currentThread().sleep(500);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }
                  }
              }
      );
      
       //...这里我只copy俩个线程根据自己测试需求来 copy
        return "线程运行";
    }
    
    /**
     * @Description: 创建线程示例方法
     * @Date: 2021/1/26 19:28
     */
    private void asyncRun(){
        asyncServiceExecutor.execute(
                new TimerTask() {
                    @Override
                    public void run() {
                       String name=Thread.currentThread().getName();
                        for (int i = 1; i <= totalRunNum; i++) {
                            System.out.println(name+":第"+i+"次测试");
                            if (i==totalRunNum){
                                System.out.println(name+"结束。");
                            }
                        }
                    }
                }
        );
    }
}    

execute(Runable)方法执行过程

如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maxPoolSize,建新的线程来处理被添加的任务。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maxPoolSize,那么通过handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

如果没看懂的话看看下面这个(个人理解版)

假设 一个任务需求需要一个线程实现。

corePoolSize 基本线程数量

workQueue 缓冲队列

  • 任务需求数量<corePoolSize,需求会被线程相应处理,且会有线程闲置。
  • 任务需求数量=corePoolSize,需求会被线程相应处理,无线程闲置。
  • 任务需求数量>corePoolSize, 如workQueue未满且能容下剩余需求量,则部分需求会被线程相应处理,剩余任务需求进入列队排队,等待闲置的线程。
  • 任务需求数量>corePoolSize,如workQueue已满活不能容下剩余需求量,则部分需求会被线程相应处理,创建临时线程处理(此时总线程数量不会大于最大线程数量)。

显示结果

示例情况1

corePoolSize: 3 基本线程
maxPoolSize: 4 最大线程
queueCapacity: 1 列队
totalRunNum=20; //运行次数
totalNum=3; //实际运行线程数量(任务需求量)

这里只截取了后部分的显示情况,由于测试运行次数少,并发不是很明显,在线程3结束前线程1/2都有运行,基本情况3条线程并发运行!

在这里插入图片描述

示例情况2

corePoolSize: 3 基本线程
maxPoolSize: 3 最大线程
queueCapacity: 1 列队
totalRunNum=20; //运行次数
totalNum=4; //实际运行线程数量(任务需求量)

可以明显的看到前面三条线基本线程处理三个任务需求,第四个任务需求进入列队排队,等待线程1结束后,再重新调用线程1来执行第4个需求,符合上述的执行过程。

在这里插入图片描述

示例情况3

corePoolSize: 3 基本线程
maxPoolSize: 4 最大线程
queueCapacity: 0 列队
totalRunNum=20; //运行次数
totalNum=4; //实际运行线程数量(任务需求量)

示例3,最大线程是4条,基本是3条,列队不能排队,任务需求是4条,线程池在基本线程的基础上再创建了一条临时线程4,来处理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WXE2jYZL-1611664899760)(https://uploader.shimo.im/f/64kUc1zjoBuwJwWj.png!thumbnail?fileGuid=DcyK6x38cvthQGtR)]

示例情况4

corePoolSize: 3 基本线程
maxPoolSize: 3 最大线程
queueCapacity: 0 列队
totalRunNum=20; //运行次数
totalNum=4; //实际运行线程数量(任务需求量)

现在是最大三个线程,且列队不能排队,4个任务需求,线程池最大只能创建3个,所以出现红色框框线程池外的新线程处理的(并不是线程池里创建的)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6q9J1bZh-1611664899762)(https://uploader.shimo.im/f/Q4J6x0SOmOT1Nh7q.png!thumbnail?fileGuid=DcyK6x38cvthQGtR)]
制作不易点个赞支持一下,谢谢各位CXY!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值