JUC之Executors的4种快捷创建线程池的方法

这篇具有很好参考价值的文章主要介绍了JUC之Executors的4种快捷创建线程池的方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JUC之Executors的4种快捷创建线程池的方法

Java通过Executors工厂类提供了4种快捷创建线程池的方法,具体如下:

newSingleThreadExecutor()//创建只有一个线程的线程池
newFixedThreadPool(int nThreads)//创建固定大小的线程池
newCachedThreadPool()//创建一个不限制线程数量的线程池,任何提交的任务都将立即执行,但是空闲线程会得到及时回收
newScheduledThreadPool()//创建一个可定期或者延时执行任务的线程池
newSingleThreadExecutor创建“单线程化线程池”
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class CreateThreadPoolDemo1 {
    public static final int SLEEP_GAP = 500;
    static class TargetTask implements Runnable{
        static AtomicInteger taskNo = new AtomicInteger(1);
        private String taskName;
        public TargetTask(){
            taskName = "task-" + taskNo.get();
            taskNo.incrementAndGet();
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"任务:"+taskName+"doing");
            try {
                Thread.sleep(SLEEP_GAP);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"运行结束。");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for(int i=0;i<5;i++){
            pool.execute(new TargetTask());
            pool.submit(new TargetTask());
        }
        Thread.sleep(1000);
        pool.shutdown();
    }
}

pool-1-thread-1任务:task-1doing
pool-1-thread-1运行结束。
pool-1-thread-1任务:task-2doing
pool-1-thread-1运行结束。
pool-1-thread-1任务:task-3doing
pool-1-thread-1运行结束。
pool-1-thread-1任务:task-4doing
pool-1-thread-1运行结束。
pool-1-thread-1任务:task-5doing
pool-1-thread-1运行结束。
pool-1-thread-1任务:task-6doing
pool-1-thread-1运行结束。

  1. 单线程化的线程池中的任务是按照提交的次序顺序执行的。
  2. 池中的唯一线程的存活时间是无限的。
  3. 当池中的唯一线程正繁忙时,新提交的任务实例会进入内部 的阻塞队列中,并且其阻塞队列是无界的。
  4. 适用于任务按照提交次序,一个任务一个任务饿逐个执行的场景。
newFixedThreadPool创建“固定数量的线程池”
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CreateThreadPoolDemo2 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(3);
        for(int i=0;i<5;i++){
            pool.execute(new TargetTask());
            pool.submit(new TargetTask());
        }
        Thread.sleep(1000);
        pool.shutdown();
    }
    public static final int SLEEP_GAP = 500;
    static class TargetTask implements Runnable{
        static AtomicInteger taskNo = new AtomicInteger(1);
        private String taskName;
        public TargetTask(){
            taskName = "task-" + taskNo.get();
            taskNo.incrementAndGet();
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"任务:"+taskName+"doing");
            try {
                Thread.sleep(SLEEP_GAP);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"运行结束。");
        }
    }
}

pool-1-thread-1任务:task-1doing
pool-1-thread-2任务:task-2doing
pool-1-thread-3任务:task-3doing
pool-1-thread-1运行结束。
pool-1-thread-3运行结束。
pool-1-thread-2运行结束。
pool-1-thread-1任务:task-4doing
pool-1-thread-2任务:task-5doing
pool-1-thread-3任务:task-6doing
pool-1-thread-3运行结束。
pool-1-thread-1运行结束。
pool-1-thread-2运行结束。
pool-1-thread-1任务:task-8doing
pool-1-thread-3任务:task-7doing
pool-1-thread-2任务:task-9doing
pool-1-thread-2运行结束。
pool-1-thread-1运行结束。
pool-1-thread-3运行结束。
pool-1-thread-2任务:task-10doing
pool-1-thread-2运行结束。

  1. 如果线程数没有达到“固定数量”,每次提交一个任务线程池内就创建一个新线程,直到线程达到线程池固定的数量。
  2. 线程池的大小一旦达到“固定数量”就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
  3. 在接收异步任务的执行目标实例时,如果池中的所有线程均在繁忙状态,新任务会进入阻塞队列中(无界的阻塞队列)。
  4. 适用于需要任务长期执行的场景。
  5. 弊端:内部使用无界队列来存放排队任务,当大量任务超过线程池最大容量需要处理时,队列无限增大,使服务器资源迅速耗尽。
newCachedThreadPool创建“可缓存线程池”
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CreateThreadPoolDemo3 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            pool.execute(new TargetTask());
            pool.submit(new TargetTask());
        }
        Thread.sleep(1000);
        pool.shutdown();
    }
    public static final int SLEEP_GAP = 500;
    static class TargetTask implements Runnable{
        static AtomicInteger taskNo = new AtomicInteger(1);
        private String taskName;
        public TargetTask(){
            taskName = "task-" + taskNo.get();
            taskNo.incrementAndGet();
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"任务:"+taskName+"doing");
            try {
                Thread.sleep(SLEEP_GAP);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"运行结束。");
        }
    }
}

pool-1-thread-1任务:task-1doing
pool-1-thread-2任务:task-2doing
pool-1-thread-3任务:task-3doing
pool-1-thread-4任务:task-4doing
pool-1-thread-5任务:task-5doing
pool-1-thread-6任务:task-6doing
pool-1-thread-7任务:task-7doing
pool-1-thread-8任务:task-8doing
pool-1-thread-9任务:task-9doing
pool-1-thread-10任务:task-10doing
pool-1-thread-9运行结束。
pool-1-thread-8运行结束。
pool-1-thread-4运行结束。
pool-1-thread-1运行结束。
pool-1-thread-7运行结束。
pool-1-thread-5运行结束。
pool-1-thread-10运行结束。
pool-1-thread-2运行结束。
pool-1-thread-3运行结束。
pool-1-thread-6运行结束。

  1. 在接收新的异步任务target执行目标实例时,如果池内所有线程繁忙,此线程池就会添加新线程来处理任务。
  2. 此线程池不会对线程池大小进行限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
  3. 如果部分线程空闲,也就是存量线程的数量超过了处理任务数量,就会回收空闲(60秒不执行任务)线程。
  4. 适用场景:需要快速处理突发性强、耗时较短的任务场景,如Netty的NIO处理场景、REST API接口的瞬时削峰场景。
  5. 弊端:没有最大线程数量限制,如果大量的异步任务执行目标实例同时提交,可能回因为创建过多线程而导致资源耗尽。
newScheduledThreadPool创建“可调度线程池”
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class CreateThreadPoolDemo4 {
    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
        for (int i = 0; i < 4; i++) {
            service.scheduleAtFixedRate
                    (new CreateThreadPoolDemo1.TargetTask(),0,1000, TimeUnit.MILLISECONDS);
//            service.scheduleWithFixedDelay
//                    (new CreateThreadPoolDemo1.TargetTask(),0,1000,TimeUnit.MILLISECONDS);
        }
        Thread.sleep(1000);
        service.shutdown();
    }
    public static final int SLEEP_GAP = 500;
    static class TargetTask implements Runnable{
        static AtomicInteger taskNo = new AtomicInteger(1);
        private String taskName;
        public TargetTask(){
            taskName = "task-" + taskNo.get();
            taskNo.incrementAndGet();
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"任务:"+taskName+"doing");
            try {
                Thread.sleep(SLEEP_GAP);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"运行结束。");
        }
    }
}

​ newScheduledThreadPool工厂方法可以创建一个执行“延时”和 “周期性”任务的可调度线程池,所创建的线程池为 ScheduleExecutorService类型的实例。ScheduleExecutorService接 口中有多个重要的接收被调目标任务的方法,其中 scheduleAtFixedRate和scheduleWithFixedDelay使用得比较多。

scheduleAtFixedRate:

public ScheduledFuture<?> scheduleAtFixedRate(
	Runnable command, //异步任务target执行目标实例
    long initialDelay, //首次执行延时
	long period, //两次开始执行最小间隔时间
    TimeUnit unit //所设置的时间的计时单位,如TimeUnit.SECONDS常量
);

scheduleWithFixedDelay:

public ScheduledFuture<?> scheduleWithFixedDelay(
    Runnable command, //异步任务target执行目标实例
    long initialDelay, //首次执行延时
    long delay, //前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)
    TimeUnit unit //所设置的时间的计时单位,如TimeUnit.SECONDS常量
);
  1. 当被调任务的执行时间大于指定的间隔时间时, ScheduleExecutorService并不会创建一个新的线程去并发执行这个任 务,而是等待前一次调度执行完毕。
  2. 适用场景:周期性地执行任务的场景。
Executors快捷创建线程池的潜在问题
FixedThreadPool和SingleThreadPool

​ 这两个工厂方法所创建的线程池,工作队列(任务排队的队列)的长度都为Integer.MAX_VALUE,可能会堆积大量的任务,从而导致OOM(即耗尽内存资源)。

CachedThreadPool和ScheduledThreadPool

​ 这两个工厂方法所创建的线程池允许创建的线程数量为Integer.MAX_VALUE,可能会导致创建大量的线程,从而导致OOM。文章来源地址https://www.toymoban.com/news/detail-419315.html

到了这里,关于JUC之Executors的4种快捷创建线程池的方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java - JUC(java.util.concurrent)包详解,其下的锁、安全集合类、线程池相关、线程创建相关和线程辅助类、阻塞队列

    JUC是java.util.concurrent包的简称,在Java5.0添加,目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题 java.lang.Thread.State tools(工具类):又叫信号量三组工具类,包含有 CountDownLatch(闭锁) 是一个同步辅助类,在完成一组正在其他线程中

    2024年02月05日
    浏览(29)
  • Kotlin Executors线程池newSingleThreadExecutor单线程

    seq-1 tid:22 -start seq-1 tid:22 -end seq-2 tid:22 -start seq-2 tid:22 -end seq-3 tid:22 -start seq-3 tid:22 -end seq-4 tid:22 -start seq-4 tid:22 -end seq-5 tid:22 -start seq-5 tid:22 -end Process finished with exit code 0     Java线程池:ExecutorService,Executors_executorservice线程池_zhangphil的博客-CSDN博客 简单的Java线程池可以从

    2024年02月12日
    浏览(23)
  • NO.17 JAVA中创建线程池的五种方法

    JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用。另一类是通过ThreadPoolExecutor类进行自定义创建。 目录 一、通过Executors类提供的方法。 1、newCachedThreadPool 2、newFixedThreadPool 3、newScheduledThreadPool 4、newSingleThreadExec

    2024年02月08日
    浏览(35)
  • JUC编程之——线程的start方法及底层源码

    简单的写一个线程的小栗子: 查看java start()方法的源码: 更加底层的C++代码: thread.c (代码位置:openJDKsrcsharenativejavalang) jvm.cpp (代码位置:openIDKhotspotsrcsharevmprims) thread.cpp (代码位置:openJDKhotspotsrcsharevmruntime) 代码——OpenJDK源码网址:http://openjdk.java.net/ 2.3.1 thre

    2023年04月13日
    浏览(32)
  • kafka Consumer 消费者使用多线程并发执行,并保证顺序消费, 第一种使用纯线程方式、第二种使用Executors线程池

    网上搜索kafka消费者通过多线程进行顺序消费的内容都不太理想,或者太过复杂,所以自己写了几个demo,供大家参考指正。         单个消费者,每秒需要处理1000条数据,每条数据的处理时间为500ms,相同accNum(客户账号)的数据需要保证消费的顺序。 1、如果1秒钟生产

    2024年02月15日
    浏览(31)
  • 嵌套for循环在外层循环和内层循环中使用两个Executors.newCachedThreadPool缓存线程池执行操作

    1. 首先,我们需要创建两个ExecutorService对象,这两个对象将作为我们的缓存线程池。 2. 然后,我们使用嵌套的for循环来执行我们的操作。在每个外层循环中,我们将创建一个新的任务并提交给外层线程池。在这个任务中,我们将创建一个新的内层循环,并在每个内层循环中创

    2024年02月07日
    浏览(29)
  • mac快捷创建文件的方法

     在macbook的使用中,当我们在桌面或访达等地方使用右键时,可以看到新建文件夹的选项,却怎么也找不到创建文件的选项。这种情况有时候会带来不便。这篇文章给大家带来一个非常简单解决这个问题。  在App Store中搜索并下载这款软件  下载完成后打开软件,如下图所

    2024年01月17日
    浏览(26)
  • JUC之线程、线程池

    start方法开启一个新线程,异步执行。 run方法同步执行,不会产生新的线程。 start方法只能执行一次,run方法可以执行多次。 sleep() 线程睡眠 两种方式调用: 线程打断 interrupt()这种方式打断,线程会抛出InterruptedException异常。比如在线程睡眠的时候,调用interrupt(),线程抛出

    2024年04月27日
    浏览(27)
  • 【Linux】线程终结篇:线程池以及线程池的实现

    linux线程完结 文章目录 前言 一、线程池的实现 二、了解性知识 1.其他常见的各种锁 2.读者写者问题 总结 什么是线程池呢? 线程池一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行

    2024年02月12日
    浏览(26)
  • 线程池的核心线程数该怎么设置

    为什么要用线程池?线程池中的线程可以重复利用,避免了重复创建线程造成的资源开销。在线程的执行时间比较短,任务比较多的时候非常适合用线程池。 如果运行的线程少于核心线程,会尝试去开启一个新的核心线程(addWorker),如果有空间的核心线程,也不会去使用,

    2024年02月08日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包