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

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


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,DiscardOldestPolicy和DiscardPolicy

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)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • iphone越狱pp助手源_pp助手越狱版源地址

    iphone越狱pp助手源_pp助手越狱版源地址在为方便大家查看核桃同学分享的每日文章,建议小伙伴们【置顶我们】的公众号哦!进入【米乐科技】公众号,点击右上角打开设置界面,再次右上角选择【置顶/星标】,这样就可以啦!苹果越狱教程篇其实在编辑这篇文章的时候,核桃同学还在纠结是分享实用软件呢,还是先分享玩机技巧。恰好有小伙伴留言说想了解越狱只是,于是乎本文就诞生了。在往期的发布中,苹果机的资源分享的较少。主要是因为苹果手机在官家IOS系统…

    2022年10月29日
  • 零拷贝详解_深拷贝和浅拷贝如何实现

    零拷贝详解_深拷贝和浅拷贝如何实现一、概念1、用户态与内核态⽤户态和内核态是操作系统的两种运⾏状态。(1)内核态:处于内核态的CPU可以访问任意的数据,包括外围设备,⽐如⽹卡、硬盘等,处于内核态的CPU可以从⼀个程序切换到另外⼀个程序,并且占⽤CPU不会发⽣抢占情况,⼀般处于特权级0的状态我们称之为内核态。(2)⽤户态:处于⽤户态的CPU只能受限的访问内存,并且不允许访问外围设备,⽤户态下的CPU不允许独占,也就是说CPU能够被其他程序获取。注意:1)为什么要有⽤户态和内核态呢?  这个主要是访问能⼒的限制

    2022年9月13日
  • docker的端口映射_docker修改端口映射

    docker的端口映射_docker修改端口映射1.downloadimage:docker@default:/root#dockerpullmikeraab/hello-earth:latest2.createandstartcontainer(docker主机IP:192.168.99.101)a)默认大写-P自动映射$docker@default:/root#dockerrun-d

    2022年10月17日
  • Python数据类型有几种「建议收藏」

    Python数据类型有几种「建议收藏」数据类型是每种编程语言必备属性,只有给数据赋予明确的数据类型,计算机才能对数据进行处理运算,因此,正确使用数据类型是十分必要的,不同的语言,数据类型类似,但具体表示方法有所不同,以下是Python编程常用的数据类型:1.数字类型Python数字类型主要包括int(整型)、long(长整型)和float(浮点型),但是在Python3中就不再有long类型了。int(整型)在…

    2022年6月6日
  • idea 在线激活码4月_通用破解码「建议收藏」

    idea 在线激活码4月_通用破解码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月15日
  • git log退出方法

    git log退出方法

    2021年10月23日

发表回复

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

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