java创建线程池的几种方式_Java中的线程池

java创建线程池的几种方式_Java中的线程池Java创建线程池线程池:4大方法,7大参数,4种拒绝策略池化技术:把一些能够复用的东西(比如说数据库连接、线程)放到池中,避免重复创建、销毁的开销,从而极大提高性能。优点:降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行;方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

Java创建线程池

线程池:4大方法,7大参数,4种拒绝策略

池化技术:把一些能够复用的东西(比如说数据库连接、线程)放到池中,避免重复创建、销毁的开销,从而极大提高性能。

优点:

  1. 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
  2. 提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行;
  3. 方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源使用率;
  4. 更强大的功能,线程池提供了定时、定期以及可控线程数等功能的线程池,使用方便简单。

线程池的创建不建议使用Executors(因为会发生内存溢出OOM),所以要通过ThreadPoolExecutors创建

四大方法

newCachedThreadPool :创建一个可缓存的无界线程池,如果线程池长度超过处理需要,可灵活回收空线程,若无可回收,则新建线程。当线程池中的线程空闲时间超过60s,则会自动回收该线程,当任务超过线程池的线程数则创建新的线程,线程池的大小上限为Integer.MAX_VALUE,可看作无限大。

newFixedThreadPool:创建一个指定大小的线程池,可控制线程的最大并发数,超出的线程会在LinkedBlockingQueue阻塞队列中等待

newSingleThreadExecutor:创建一个单线程化的线程池,它只有一个线程,用仅有的一个线程来执行任务,保证所有的任务按照指定顺序(FIFO,LIFO,优先级)执行,所有的任务都保存在队列LinkedBlockingQueue中,等待唯一的单线程来执行任务。

newScheduledThreadPool:创建一个定长的线程池,可以指定线程池核心线程数,支持定时及周期性任务的执行

public class Test1 { 
   
    public static void main(String[] args) { 
   
        ExecutorService newCachedThreadPool =  Executors.newCachedThreadPool(); //无边界,根据情况自动创建线程池大小
        ExecutorService newFixedThreadPool =  Executors.newFixedThreadPool(5);//创建一个指定大小的线程池
        ExecutorService newSingleThreadExecutor =  Executors.newSingleThreadExecutor(); //创建一个单线程化的线程池

        for (int i = 0; i < 10; i++) { 
   
            newCachedThreadPool.execute(()->{ 
   
                System.out.println(Thread.currentThread().getName());
            });
        }
        System.out.println("============================");
        for (int i = 0; i < 10; i++) { 
   
            newFixedThreadPool.execute(()->{ 
   
                System.out.println(Thread.currentThread().getName());
            });
        }
        System.out.println("============================");
        for (int i = 0; i < 10; i++) { 
   
            newSingleThreadExecutor.execute(()->{ 
   
                System.out.println(Thread.currentThread().getName());
            });
        }

    // 关闭线程池
        newCachedThreadPool.shutdown();
        newFixedThreadPool.shutdown();
        newSingleThreadExecutor.shutdown();
    }
}

七大参数

  1. corePoolSize(线程池基本大小):当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时,才会根据是否存在空闲线程,来决定是否需要创建新的线程。除了利用提交新任务来创建和启动线程(按需构造),也可以通过 prestartCoreThread() 或 prestartAllCoreThreads() 方法来提前启动线程池中的基本线程。
  2. maximumPoolSize(线程池最大大小):线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽略该参数。
  3. keepAliveTime(线程存活保持时间):默认情况下,当线程池的线程个数多于corePoolSize时,线程的空闲时间超过keepAliveTime则会终止。但只要keepAliveTime大于0,allowCoreThreadTimeOut(boolean) 方法也可将此超时策略应用于核心线程。另外,也可以使用setKeepAliveTime()动态地更改参数。
  4. unit(存活时间的单位):时间单位,分为7类,从细到粗顺序:NANOSECONDS(纳秒),MICROSECONDS(微妙),MILLISECONDS(毫秒),SECONDS(秒),MINUTES(分),HOURS(小时),DAYS(天);
  5. workQueue(任务队列):用于传输和保存等待执行任务的阻塞队列。可以使用此队列与线程池进行交互:
    1. 如果运行的线程数少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。
    2. 如果运行的线程数等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。
    3. 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
  6. threadFactory(线程工厂):用于创建新线程。由同一个threadFactory创建的线程,属于同一个ThreadGroup,创建的线程优先级都为Thread.NORM_PRIORITY,以及是非守护进程状态。threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号);
  7. handler(线程饱和策略):当线程池和队列都满了,则表明该线程池已达饱和状态。
    1. ThreadPoolExecutor.AbortPolicy:处理程序遭到拒绝,则直接抛出运行时异常 RejectedExecutionException。(默认策略)
    2. ThreadPoolExecutor.CallerRunsPolicy:调用者所在线程来运行该任务,此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
    3. ThreadPoolExecutor.DiscardPolicy:无法执行的任务将被删除。
    4. ThreadPoolExecutor.DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重新尝试执行任务(如果再次失败,则重复此过程)。
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) { 
   
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

线程池底层ThreadPoolExecutor底层实现的步骤:

  1. 当线程数小于核心线程数时,创建线程
  2. 当线程数大于等于核心线程数时,且任务队列未满时,将任务放入任务队列
  3. 当线程数大于等于核心线程数,且任务队列已满
    3.1 若线程数小于最大线程数,创建线程
    3.2 若线程数等于最大线程数,抛出异常,拒绝任务

手动创建线程池

public class Test2 { 
   
    public static void main(String[] args) { 
   
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, //核心线程数
                5,//最大线程数
                3,//超时等待时间
                TimeUnit.SECONDS,//超时等待的单位
                new LinkedBlockingQueue<>(3),//阻塞队列
                Executors.defaultThreadFactory(),//线程工厂 一般使用这个默认的
                new ThreadPoolExecutor.AbortPolicy()//拒绝策略
        );
        //当队列满时就会触发最大线程数,让他创建线程,但是不会超过给定大小5个(说白了还能创建的就是3个)
        for (int i = 0; i < 8; i++) { 
   
            executor.execute(()->{ 
   
                System.out.println(Thread.currentThread().getName());
                System.out.println("=================================");
            });
        }
    }
}

四种拒绝策略

它们分别是AbortPolicy,CallerRunsPolicy,DiscardOldestPolicyDiscardPolicy

AbortPolicy

终止策略,这是ThreadPoolExecutor线程池默认的拒绝策略,程序将会抛出RejectedExecutionException异常。

CallerRunsPolicy

调用者运行策略,线程池中没办法运行,那么就由提交任务的这个线程运行(哪儿来的回哪儿儿去~)。

DiscardOldestPolicy

丢弃最早未处理请求策略,丢弃最先进入阻塞队列的任务以腾出空间让新的任务入队列。

DiscardPolicy

丢弃策略,什么都不做,即丢弃新提交的任务。

最大线程数的设置

  1. 对于CPU密集型任务:线程池中线程个数应尽量少,不应大于CPU核心数;
System.out.println(Runtime.getRuntime().availableProcessors());
  1. 对于IO密集型任务:由于IO操作速度远低于CPU速度,那么在运行这类任务时,CPU绝大多数时间处于空闲状态,那么线程池可以配置尽量多些的线程,以提高CPU利用率;
  2. 对于混合型任务:可以拆分为CPU密集型任务和IO密集型任务,当这两类任务执行时间相差无几时,通过拆分再执行的吞吐率高于串行执行的吞吐率,但若这两类任务执行时间有数据级的差距,那么没有拆分的意义。

线程池监控

利用线程池提供的参数进行监控:

  • taskCount:线程池需要执行的任务数量。
  • completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount。
  • largestPoolSize:线程池曾经创建过的最大线程数量,通过这个数据可以知道线程池是否满过。如等于线程池的最大大小,则表示线程池曾经满了。
  • getPoolSize:线程池的线程数量。如果线程池不销毁的话,池里的线程不会自动销毁,所以这个大小只增不减。
  • getActiveCount:获取活动的线程数。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/187000.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • cad快速选择命令快捷键_CAD快捷键,命令大全

    cad快速选择命令快捷键_CAD快捷键,命令大全一 常用 CTRL ALT 快捷键 ALT TK 如快速选择 ALT NL 线性标注 ALT VV4 快速创建四个窗口 ALT MUP 提取轮廓 Ctrl B 栅格捕捉模式控制 F9 Ctrl C 将选择的对象复制到剪切板上 Ctrl F 控制是否实现对象自动捕捉 F3 Ctrl G 栅格显示模式控制 F7 Ctrl J 重复执行上一步命令 Ctrl K 超级链接 Ctrl N 新建图形文件 C

    2025年9月6日
    11
  • 使用Java判断闰年

    使用Java判断闰年我们在做这一题之前 我们首先要弄清楚什么是闰年 简而言之闰年就是可以被 4 整除不能被 100 整除 或者可以被 400 整除 那么这一年就是闰年 leapyear 然后就按照以上条件一步一步写代码 public nbsp static nbsp void nbsp main String args nbsp nbsp nbsp nbsp nbsp nbsp Scannersc newScanner System in nbsp nbsp nbsp nbsp nbsp nbsp System out printl

    2025年8月22日
    1
  • 密码找回

    密码找回

    2021年5月10日
    135
  • vb api函数用法_VB调用apdl

    vb api函数用法_VB调用apdl1、API函数    API的英文全称(ApplicationProgrammingInterface),WIN32API也就是MicrosoftWindows32位平台的应用程序编程接口,在window操作系统盛行的期间,程序员主要是利用API函数来开发Windows平台下的应用程序当时程序员必须熟记很多API函数。随着软件技术的不断发展,在Windows平台上出现了很所可视化编程

    2025年6月13日
    2
  • 从零开始的Android:常见的UI设计模式「建议收藏」

    从零开始的Android:常见的UI设计模式「建议收藏」尽管Android允许您创建几乎任何可能需要的自定义视图或用户界面,但事实证明,在正确的情况下,有一些用户界面模式可以很好地适用于用户。在本教程中,您将学习其中的一些模式,以及它们如何通过在使用应用程序时创造出色的体验来帮助用户。1.主画面用户在打开应用程序时看到的第一个屏幕通常是最重要的。从这里开始,您的用户应该能够执行快速动作并继续前进,或者进一步深入到您的应用中以完善他们…

    2022年6月21日
    28
  • 多种时间格式字符串转换为Date对象「建议收藏」

    多种时间格式字符串转换为Date对象「建议收藏」maven引入包org.apache.commonscommons-lang33.8使用类org.apache.commons.lang3.time.DateUtils调用示例Datedate=DateUtils.parseDate(strDate,”yyyy-MM-dd”,”yyyy-MM-ddHH:mm:ss”,”yyyy/MM/dd”,”yy…

    2022年9月1日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号