线程池的使用

article/2025/9/10 3:49:39

1.线程池使用场景


java中经常需要用到多线程来处理一些业务,我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理。java中涉及到线程池的相关类均在jdk1.5开始的java.util.concurrent包中,涉及到的几个核心类及接口包括:Executor、Executors、ExecutorService、ThreadPoolExecutor、FutureTask、Callable、Runnable等。

线程池可以:

加快请求响应(响应时间优先)

加快处理大任务(吞吐量优先)

使用过程

//创建线程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 10, 30, TimeUnit.SECONDS, new SynchronousQueue<>());//向线程池提交任务 无返回值threadPoolExecutor.execute(new Runnable() {@Overridepublic void run() {}});//向线程池提交任务 有返回值Future<String> submit = threadPoolExecutor.submit(new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println("threadPoolExecutor submit");return "null";}});//返回任务的执行结果try {Object o = submit.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}//关闭线程池threadPoolExecutor.shutdown();

线程池的创建

线程池可以自动创建也可以手动创建,

自动创建

自动创建体现在Executors工具类中,常见的可以创建newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool;

        //自动创建不同类型的线程池,使用Executors类,指定的参数比较少//手动创建使用 ThreadPoolExecutor ,可以指定多个参数//创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);scheduledExecutorService.schedule(new Runnable() {@Overridepublic void run() {System.out.println("延迟四秒执行");}},4, TimeUnit.SECONDS);scheduledExecutorService.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("延迟1S后,每隔3秒执行一");}},1,3,TimeUnit.SECONDS);//返回一个线程池(这个线程池只有一个线程),这个线程池可以在线程死后(或发生异常时)// 重新启动一个线程来替代原来的线程继续执行下去ExecutorService executorService = Executors.newSingleThreadExecutor();//创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程ExecutorService executorService1 = Executors.newFixedThreadPool(3);//创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们ExecutorService executorService2 = Executors.newCachedThreadPool();

手动创建

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 10, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());

手动创建体现在可以灵活设置线程池的各个参数,体现在代码中即ThreadPoolExecutor类构造器上各个实参的不同:

//手动创建线程池/*corePoolSize:核心线程数,也是线程池中常驻的线程数,线程池初始化时默认是没有线程的,当任务来临时才开始创建线程去执行任务maximumPoolSize:最大线程数,在核心线程数的基础上可能会额外增加一些非核心线程,需要注意的是只有当workQueue队列填满时才会创建多于corePoolSize的线程(线程池总线程数不超过maxPoolSize)keepAliveTime:非核心线程的空闲时间超过keepAliveTime就会被自动终止回收掉,注意当corePoolSize=maxPoolSize时,keepAliveTime参数也就不起作用了(因为不存在非核心线程);unit:keepAliveTime的时间单位workQueue:用于保存任务的队列,可以为无界、有界、同步移交new SynchronousQueue<>()三种队列类型之一,当池子里的工作线程数大于corePoolSize时,这时新进来的任务会被放到队列中threadFactory:创建线程的工厂类,默认使用Executors.defaultThreadFactory(),也可以使用guava库的ThreadFactoryBuilder来创建handler:线程池无法继续接收任务(队列已满且线程数达到maximunPoolSize)时的饱和策略,取值有AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy*/ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 10, 30, TimeUnit.SECONDS, new SynchronousQueue<>());


 

workQueue队列

SynchronousQueue(同步移交队列):队列不作为任务的缓冲方式,可以简单理解为队列长度为零
LinkedBlockingQueue(无界队列):队列长度不受限制,当请求越来越多时(任务处理速度跟不上任务提交速度造成请求堆积)可能导致内存占用过多或OOM
ArrayBlockintQueue(有界队列):队列长度受限,当队列满了就需要创建多余的线程来执行任务

 handler拒绝策略

  • AbortPolicy:中断抛出异常
  • DiscardPolicy:默默丢弃任务,不进行任何通知
  • DiscardOldestPolicy:丢弃掉在队列中存在时间最久的任务
  • CallerRunsPolicy:让提交任务的线程去执行任务(对比前三种比较友好一丢丢)

关闭线程池

shutdownNow():立即关闭线程池(暴力),正在执行中的及队列中的任务会被中断,同时该方法会返回被中断的队列中的任务列表
shutdown():平滑关闭线程池,正在执行中的及队列中的任务能执行完成,后续进来的任务会被执行拒绝策略
isTerminated():当正在执行的任务及对列中的任务全部都执行(清空)完就会返回true

线程池线程复用原理


    1.线程池里执行的是任务,核心逻辑在ThreadPoolExecutor类的execute方法中,同时ThreadPoolExecutor中维护了HashSet<Worker> workers;
    2.addWorker()方法来创建线程执行任务,如果是核心线程的任务,会赋值给Worker的firstTask属性;
    3.Worker实现了Runnable,本质上也是任务,核心在run()方法里;
    4.run()方法的执行核心runWorker(),自旋拿任务while (task != null || (task = getTask()) != null)),task是核心线程Worker的firstTask或者getTask();
    5.getTask()的核心逻辑:
            1.若当前工作线程数量大于核心线程数->说明此线程是非核心工作线程,通过poll()拿任务,未拿到任务即getTask()返回null,然后会在processWorkerExit(w, completedAbruptly)方法释放掉这个非核心工作线程的引用;
            2.若当前工作线程数量小于核心线程数->说明此时线程是核心工作线程,通过take()拿任务
            3.take()方式取任务,如果队列中没有任务了会调用await()阻塞当前线程,直到新任务到来,所以核心工作线程不会被回收; 当执行execute方法里的workQueue.offer(command)时会调用Condition.singal()方法唤醒一个之前阻塞的线程,这样核心线程即可复用

 Callable和Runnable


Runnable和Callable都可以理解为任务,里面封装着任务的具体逻辑,提交给线程池执行,区别在于Runnable任务执行没有返回值,且Runnable任务逻辑中不能通过throws抛出cheched异常(但是可以try catch),而Callable可以获取到任务的执行结果返回值且抛出checked异常。

Future和FutureTask


Future接口用来表示执行异步任务的结果存储器,当一个任务的执行时间过长就可以采用这种方式:把任务提交给子线程去处理,主线程不用同步等待,当向线程池提交了一个Callable或Runnable任务时就会返回Future,用Future可以获取任务执行的返回结果。

Future的主要方法包括:

get()方法:返回任务的执行结果,若任务还未执行完,则会一直阻塞直到完成为止,如果执行过程中发生异常,则抛出异常,但是主线程是感知不到并且不受影响的,除非调用get()方法进行获取结果则会抛出ExecutionException异常;


get(long timeout, TimeUnit unit):在指定时间内返回任务的执行结果,超时未返回会抛出TimeoutException,这个时候需要显式的取消任务;


cancel(boolean mayInterruptIfRunning):取消任务,boolean类型入参表示如果任务正在运行中是否强制中断;


isDone():判断任务是否执行完毕,执行完毕不代表任务一定成功执行,比如任务执行失败但也执行完毕、任务被中断了也执行完毕都会返回true,它仅仅表示一种状态说后面任务不会再执行了;


isCancelled():判断任务是否被取消;
 


http://chatgpt.dhexx.cn/article/Lonc999V.shtml

相关文章

线程池_线程池详解

1 线程池使用场景&#xff1f; java中经常需要用到多线程来处理一些业务&#xff0c;我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程&#xff0c;那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险&…

Netty 线程池

Netty的线程池有什么样的特性 Java 原生线程池 Java 原生的线程池主要有三种&#xff1a;ThreadPoolExecutor、ScheduledThreadPoolExecutor、ForkJoinPool。 ThreadPoolExecutor 是最古老的类&#xff0c;我们通常说的线程池&#xff0c;也是指这个类。 ScheduledThreadPoo…

Linux —— 线程池

目录 一、什么是线程池 二、线程池的优点 三、线程池的应用 四、实现一个简单的线程池 五、单例模式 1. 饿汉实现方式 2. 懒汉实现方式 3. 单例模式实现线程池&#xff08;懒汉方式&#xff09; 六、其他常见的各种锁 一、什么是线程池 线程池是线程的一种使用模式。在…

线程池的实现原理

系统学习性&#xff0c;移步 IT-BLOG 线程池做的工作主要是控制运行的线程数量&#xff0c;处理过程中将任务放入队列&#xff0c;然后在线程创建后启动这些任务&#xff0c;如果线程数超过了最大数量超出数量的线程排队等候&#xff0c;等其他线程执行完毕&#xff0c;再从队列…

java——线程池

一、线程池 线程池可以看做是线程的集合。它的工作主要是控制运行的线程的数量&#xff0c;处理过程中将任务放入队列&#xff0c;然后在线程创建后 启动这些任务&#xff0c;如果线程数量超过了最大数量超出数量的线程排队等候&#xff0c;等其它线程执行完毕&#xff0c; 再…

java线程池(详解)

线程池介绍 线程池&#xff08;thread pool&#xff09;&#xff1a;一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;对线程统一管理。 线程池就是存放线程的池子&#xff0c;池子里存放了很多可以复…

Java线程池详解

本文包含知识点 线程池的使用场景分析线程池的创建及重要参数线程池实现线程复用的原理springboot中使用线程池Callabel与Runnable任务在基于spring体系的业务中正确地关闭线程池实现优先使用运行线程及调整线程数大小的线程池(线程池的优化)在java web项目中慎用Executors以及…

C++线程池

1.基础概念 线程池&#xff1a;一种线程的使用模式&#xff0c;线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性。而线程池维护着多个线程&#xff0c;等待监督管理者分配可并行执行的任务。这样避免了在短时间内创建和销毁线程的代价。线程池不仅能够内核的充分…

线程池详解

成功不是将来才有的&#xff0c;而是从决定去做的那一刻起&#xff0c;持续累积而成。 目录 背景 线程池介绍 线程池使用 Executors 线程池如何关闭&#xff1f; 面试题 总结 背景 下面是一段创建线程并运行的代码: for (int i 0; i < 100; i) {new Thread(() -&…

线程池(通俗易懂)

目录 一、什么是线程池 二、创建线程池的方式 三、线程池的七大参数 四、四种拒绝策略 1.AbortPolicy() 2.CallerRunsPolicy() 3.DiscardPolicy() 4.DiscardOldestPolicy() 五、自定义一个线程池 1.场景描述 2.代码实现 一、什么是线程池 线程池其实就是一种多线程处理…

线程池研发学习笔记

线程池研发 线程池 线程池基础 概念介绍 1:什么是线程池 可以直接叙述,也可以对比连接池介绍 线程池其实就是一种多线程处理形式&#xff0c;处理过程中可以将任务添加到队列中&#xff0c;然后在创建线程后自动启动这些任务。这里的线程就是我们前面学过的线程,这里的任务就是…

线程池是什么?线程池(ThreadPoolExecutor)使用详解

点一点&#xff0c;了解更多https://www.csdn.net/ 本篇文章将详细讲解什么是线程池&#xff0c;线程池的参数介绍&#xff0c;线程池的工作流程&#xff0c;使用Executors创建常见的线程池~~~ 目录 点一点&#xff0c;了解更多 文章目录 一、线程池的概念 1.1线程池的目的…

写给小白看的线程池,还有10道面试题

如何搞定20k的面试小抄 为什么要用线程池呢&#xff1f; 下面是一段创建线程并运行的代码: for (int i 0; i < 100; i) {new Thread(() -> {System.out.println("run thread->" Thread.currentThread().getName());userService.updateUser(....);}).start…

线程池详解(通俗易懂超级好)

目标 【理解】线程池基本概念 【理解】线程池工作原理 【掌握】自定义线程池 【应用】java内置线程池 【应用】使用java内置线程池完成综合案例 线程池 线程池基础线程池使用线程池综合案例学员练习线程池总结 概念介绍 什么是线程池为什么使用线程池线程池有哪些优势 什么…

Java 多线程:彻底搞懂线程池

熟悉 Java 多线程编程的同学都知道&#xff0c;当我们线程创建过多时&#xff0c;容易引发内存溢出&#xff0c;因此我们就有必要使用线程池的技术了。 目录 1 线程池的优势 2 线程池的使用 3 线程池的工作原理 4 线程池的参数 4.1 任务队列&#xff08;workQueue&#x…

GridView概述

一、使用GridView以表格形式显示多张图片 GridView用于在界面上按行、列分布的方式来显示多个组件 二、使用GridView 1、java代码 import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterV…

Master-Detail GridView

梦幻版Master-Detail GridView(黄忠成) 2007-12-26 09:34 前面的Master-Detail GridView控件應用&#xff0c;相信你已在市面上的書、或網路上見過&#xff0c;但此節中的GridView控件應用包你沒看過&#xff0c;但一定想過&#xff01;請見圖4-8-63。 圖4-8-63 圖 4-8-64 你一…

GridView DataGrid

ASP.NET 2.0提供了功能强大的数据绑定控件GridView、在使用中&#xff0c;一些属性和方法经常会与ASP.NET 1.1中的DataGrid混淆(VS2005中依然可以使用DataGrid&#xff0c;手动添加到工具箱或HTML状态输入代码)&#xff0c;下面我们分别用GridView和DataGrid实现其数据绑定、编…

GridView详讲

GridView是ASP.NET界面开发中的一个重要的控件&#xff0c;对GridView使用的熟练程度直接影响软件开发的进度及功能的实现。(车延禄) GridView的主要新特性&#xff1a; 1.与DataSource控件结合实现了显示与数据操作的分离&#xff0c;大大减化了代码的编写量; 2.实现"双向…

GridView详述

GridView无代码分页排序GridView选中&#xff0c;编辑&#xff0c;取消&#xff0c;删除GridView正反双向排序GridView和下拉菜单DropDownList结合GridView和CheckBox结合鼠标移到GridView某一行时改变该行的背景色方法一鼠标移到GridView某一行时改变该行的背景色方法二GridVi…