IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 线程池详解+springboot整合线程池(超级详细简洁代码可直接执行) -> 正文阅读

[Java知识库]线程池详解+springboot整合线程池(超级详细简洁代码可直接执行)

一、概念

与数据库连接池的原理类似,线程池就是将多个线程对象放入一个池子里面,之后从该池子中获取、实用和回收线程。有两点需要明确。1. 每一个线程,在一段时间内只能执行一个任务。2. 线程池中的各个线程是可以重复使用的。

二、线程池的创建方式

  1. Executors.newSingleThreadExecutor() 创建只有一个线程的线程池。其底层源码如下:

    public static ExecutorService newSingleThreadExecutor() {
     ? ? ? ?return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
     ?  }

    其中可以发现,线程只有一个,但是等待队列是Integer.MAX_VALUE大的。

  2. Executors.newCachedThreadPool() 创建可以放多个线程的线程池。其底层源码如下:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

????????其中可以发现,线程有Integer.MAX_VALUE个,其中SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列。

????3. Executors.newFixedThreadPool(5) 创建固定线程数的线程池。其底层源码如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

其中可以发现,线程数是指定的,等待队列是Integer.MAX_VALUE大的。

? 4. Executors.newSingleThreadScheduledExecutor() 创建一个可用于任务调度的线程池。其底层源码如下:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
 ? ?return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
 ? ?super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}

其中可以发现核心线程数为1,但是最大线程数为Integer.MAX_VALUE,等待队列是一个延迟无界队列

5. Executors.newScheduledThreadPool(5) 创建一个可用于任务调度的线程池,并且线程是有多个的。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
 ? ?return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
 ? ?super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}

可以发现,除了核心线程数跟newSingleThreadScheduledExecutor()不一样,其他的都一样。

特别说明:

????????阿里巴巴编程规范中特意强调,禁止使用上面五种方式创建线程池。其实我们也可以从中发现,以上线程池中,要么是最大线程数没有限制,要么是其中的等待队列的大小没有限制(Integer.MAX_VALUE可以被认为是没有限制),那么就有可能将内存撑爆,导致系统崩溃。所以工作中一定不要用上面的方式创建数据库。

那么应该怎样创建数据库呢?

创建数据库的正确姿势如下:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,2,3, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),new ThreadPoolExecutor.AbortPolicy());

其实就是上面那些创建线程池有系统自动赋值的参数,改成我们手动赋值

public ThreadPoolExecutor(int corePoolSize,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int maximumPoolSize,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?long keepAliveTime,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?TimeUnit unit,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BlockingQueue<Runnable> workQueue,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?RejectedExecutionHandler handler) {
 ? ? ? ?this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
 ? ? ? ? ? ? Executors.defaultThreadFactory(), handler);
 ?  }

线程池的参数说明:

  1. corePoolSize:核心线程数

  2. maximumPoolSize:最大线程数

  3. keepAliveTime:最大空闲时间

  4. unit:最大空闲时间单位

  5. workQueue:任务队列

  6. handler:拒绝策略,有以下四种

    (1)ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。

    (2)ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。

    (3)ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。

    (4)ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。

    也可以自己实现RejectedExecutionHandler接口来自定义拒绝策略

下面附上SpringBoot整合线程的代码:

代码的结构图,方便读者查看

?

@RestController
public class ThreadController {
?
 ? ?@Autowired
 ? ?private AsyncService asyncService;
?
 ? ?@Autowired
 ? ?private ThreadPoolTaskExecutor threadPool;
?
 ? ?@RequestMapping("test")
 ? ?public void testAsync() throws InterruptedException {
 ? ? ? ?System.out.println("testAsync 执行开始");
 ? ? ? ?TimeUnit.SECONDS.sleep(2);
 ? ? ? ?asyncService.executeAsync();
 ? ? ? ?System.out.println("testAsync 执行完毕");
 ?  }
?
 ? ?@RequestMapping("testThreadPool")
 ? ?public void testThreadPool() throws InterruptedException {
 ? ? ? ?System.out.println("testThreadPool start");
 ? ? ? ?TimeUnit.SECONDS.sleep(2);
 ? ? ? ?threadPool.execute(() -> System.out.println("threadPool testThreadPool"));
 ? ? ? ?System.out.println("testThreadPool end");
 ?  }
}
public interface AsyncService {
 ? ?/**
 ? ? * 执行异步任务
 ? ? */
 ? ?void executeAsync();
}
@Service
public class AsyncServiceImpl implements AsyncService {
?
 ? ?private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);
?
 ? ?@Async("asyncServiceExecutor")
// ?  @Resource(name = "asyncServiceExecutor")
 ? ?@Override
 ? ?public void executeAsync() {
 ? ? ? ?logger.info("start executeAsync");
 ? ? ? ?System.out.println("start executeAsync");
 ? ? ? ?System.out.println("当前运行的线程名称:" + Thread.currentThread().getName());
 ? ? ? ?logger.info("end executeAsync");
 ? ? ? ?System.out.println("end executeAsync");
 ?  }
}
@Configuration
@EnableAsync
@Data
public class ExecutorConfig {
?
 ? ?@Value("${async.executor.thread.core_pool_size}")
 ? ?private int corePoolSize;
?
 ? ?@Value("${async.executor.thread.max_pool_size}")
 ? ?private int maxPoolSize;
?
 ? ?@Value("${async.executor.thread.queue_capacity}")
 ? ?private int queueCapacity;
?
 ? ?@Value("${async.executor.thread.name.prefix}")
 ? ?private String namePrefix;
?
 ? ?@Bean(name = "asyncServiceExecutor")
 ? ?public ThreadPoolTaskExecutor asyncServiceExecutor(){
 ? ? ? ?ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
 ? ? ? ?threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
 ? ? ? ?threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
 ? ? ? ?threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
 ? ? ? ?threadPoolTaskExecutor.setKeepAliveSeconds(3);
 ? ? ? ?threadPoolTaskExecutor.setThreadNamePrefix(namePrefix);
 ? ? ? ?// rejection-policy:当pool已经达到max size的时候,如何处理新任务
 ? ? ? ?// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
 ? ? ? ?threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
 ? ? ? ?//加载
 ? ? ? ?threadPoolTaskExecutor.initialize();
 ? ? ? ?return threadPoolTaskExecutor;
 ?  }
}

application.yml配置

async:
  executor:
 ?  thread:
 ? ? ?# 配置核心线程数
 ? ?  core_pool_size: 10
 ? ? ?# 配置最大线程数
 ? ?  max_pool_size: 20
 ? ? ?# 配置队列大小
 ? ?  queue_capacity: 999
 ? ?  name:
 ? ? ?  prefix: async-service-

以上就是springboot整合线程池的代码,读者可以直接拷贝下来运行。这里整合Controller里面有两种用法,一种是用service的实现方法去异步执行;另外一种是直接将ThreadPoolTaskExecutor注入到Controller中来调用执行。读者可以自行体会。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-20 12:21:41  更:2021-10-20 12:23:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:17:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码