java自带的四种线程池实例详解

 更新时间:2022年04月25日 16:54:00   作者:魔法二少  
java线程的创建非常昂贵,需要JVM和OS(操作系统)互相配合完成大量的工作,下面这篇文章主要给大家介绍了关于java自带的四种线程池的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下

java预定义的哪四种线程池?

  • newSingleThreadExexcutor:单线程数的线程池(核心线程数=最大线程数=1)
  • newFixedThreadPool:固定线程数的线程池(核心线程数=最大线程数=自定义)
  • newCacheThreadPool:可缓存的线程池(核心线程数=0,最大线程数=Integer.MAX_VALUE)
  • newScheduledThreadPool:支持定时或周期任务的线程池(核心线程数=自定义,最大线程数=Integer.MAX_VALUE)

四种线程池有什么区别?

上面四种线程池类都继承ThreadPoolExecutor,在创建时都是直接返回new ThreadPoolExecutor(参数),它们的区别是定义的ThreadPoolExecutor(参数)中参数不同,而ThreadPoolExecutor又继承ExecutorService接口类

  • newFixedThreadPool

定义:
xecutorService executorService=Executors.newFixedThreadPool(2);

缺点:使用了LinkBlockQueue的链表型阻塞队列,当任务的堆积速度大于处理速度时,容易堆积任务而导致OOM内存溢出

  • newSingleThreadExecutor

定义:ExecutorService executorService =Executors.newSingleThreadExecutor();

上面代码神似new FixedThreadPoop(1),但又有区别,因为外面多了一层FinalizableDelegatedExecutorService,其作用:

可知,fixedExecutorService的本质是ThreadPoolExecutor,所以fixedExecutorService可以强转成ThreadPoolExecutor,但singleExecutorService与ThreadPoolExecutor无任何关系,所以强转失败,故newSingleThreadExecutor()被创建后,无法再修改其线程池参数,真正地做到single单个线程。

缺点:使用了LinkBlockQueue的链表型阻塞队列,当任务的堆积速度大于处理速度时,容易堆积任务而导致OOM内存溢出

newCacheThreadPool

定义:ExecutorService executorService=Executors.newCacheThreadPool();

缺点:SynchronousQueue是BlockingQueue的一种实现,它也是一个队列,因为最大线程数为Integer.MAX_VALUE,所有当线程过多时容易OOM内存溢出

ScheduledThreadPool

定义:ExecutorService executorService=Executors.newScheduledThreadPool(2);

源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        //ScheduledThreadPoolExecutor继承ThreadPoolExecutor
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    
public ScheduledThreadPoolExecutor(int corePoolSize) {
    //ScheduledThreadPoolExecutor继承ThreadPoolExecutor,故super()会调用ThreadPoolExecutor的构造函数初始化并返回一个ThreadPoolExecutor,而ThreadPoolExecutor使实现ExecutorService接口的
    //最终ScheduledThreadPoolExecutor也和上面几种线程池一样返回的是ExecutorService接口的实现类ThreadPoolExecutor
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

线程池有哪几个重要参数?

ThreadPoolExecutor构造方法如下:

  • keepAliveTime是指当前线程数位于 [核心线程数,最大线程数] 之间的这些非核心线程等待多久空闲时间而没有活干时,就退出线程池;
  • 等待丢列的大小与最大线程数是没有任何关系的,线程创建优先级=核心线程 > 阻塞队列 > 扩容的线程(当前核心线程数小于最大线程数时才能扩容线程)
  • 假如核心线程数5,等待队列长度为3,最大线程数10:当线程数不断在增加时,先创建5个核心线程,核心线程数满了再把线程丢进等待丢列,等待队列满了(3个线程),此时会比较最大线程数(只有等待丢列满了最大线程数才能出场),还可以继续创建2个线程(5+3+2),若线程数超过了最大线程数,则执行拒绝策略;
  • 假如核心线程数5,等待队列长度为3,最大线程数7:当线程数不断在增加时,先创建5个核心线程,核心线程数满了再把线程丢进等待丢列,当等待队列中有2个线程时达到了最大线程数(5+2=7),但是等待丢列还没满所以不用管最大线程数,直到等待丢列满了(3个阻塞线程),此时会比较最大线程数(只有等待丢列满了最大线程数才能出场),此时核心+等待丢列=5+3=8>7=最大线程数,即已经达到最大线程数了,则执行拒绝策略;
  • 如果把等待丢列设置为LinkedBlockingQueue无界丢列,这个丢列是无限大的,就永远不会走到判断最大线程数那一步了

如何自定义线程池

可以使用有界队列,自定义线程创建工厂ThreadFactory和拒绝策略handler来自定义线程池

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException, IOException {
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadFactory threadFactory = new NameTreadFactory();
        RejectedExecutionHandler handler = new MyIgnorePolicy();
       ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                workQueue, threadFactory, handler);
        executor.prestartAllCoreThreads(); // 预启动所有核心线程        
        for (int i = 1; i <= 10; i++) {
            MyTask task = new MyTask(String.valueOf(i));
            executor.execute(task);
        }
        System.in.read(); //阻塞主线程
    }
    static class NameTreadFactory implements ThreadFactory {
        private final AtomicInteger mThreadNum = new AtomicInteger(1);
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
            System.out.println(t.getName() + " has been created");
            return t;
        }
    }

    public static class MyIgnorePolicy implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            doLog(r, e);
        }
        private void doLog(Runnable r, ThreadPoolExecutor e) {
            // 可做日志记录等
            System.err.println( r.toString() + " rejected");
//          System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
        }
    }

    static class MyTask implements Runnable {
        private String name;
        public MyTask(String name) {
            this.name = name;
        }
        @Override
        public void run() {
            try {
                System.out.println(this.toString() + " is running!");
                Thread.sleep(3000); //让任务执行慢点
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public String getName() {
            return name;
        }
        @Override
        public String toString() {
            return "MyTask [name=" + name + "]";
        }
    }
}

运行结果:

其中7-10号线程被拒绝策略拒绝了,1、2号线程执行完后,3、6号线程进入核心线程池执行,此时4、5号线程在任务队列等待执行,3、6线程执行完再通知4、5线程执行

总结

到此这篇关于java自带的四种线程池的文章就介绍到这了,更多相关java四种线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mybatisplus的公共字段插入的实现

    mybatisplus的公共字段插入的实现

    这篇文章主要介绍了mybatisplus的公共字段插入,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • 详解Java多线程处理List数据

    详解Java多线程处理List数据

    这篇文章主要介绍了Java多线程处理List数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • SpringBoot中@ConditionalOnBean实现原理解读

    SpringBoot中@ConditionalOnBean实现原理解读

    这篇文章主要介绍了SpringBoot中@ConditionalOnBean实现原理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Spring自动注入失败的解决方法

    Spring自动注入失败的解决方法

    这篇文章主要介绍了Spring自动注入失败的解决方法,帮助大家更好的理解和学习使用Spring框架,感兴趣的朋友可以了解下
    2021-05-05
  • Java中的List集合初始化及常见方法解析

    Java中的List集合初始化及常见方法解析

    这篇文章主要介绍了Java中的List集合初始化及常见方法解析,List集合的特点是元素有序可重复,只要是带集合、数组的都叫有序,因若无序就不会存在有下标,本文来讲一下List集合初始化及常见方法,需要的朋友可以参考下
    2023-10-10
  • Java基础篇之List集合举例详解

    Java基础篇之List集合举例详解

    Java中的List集合是一种常用的数据结构,它提供了一种有序、可重复的元素集合,下面这篇文章主要给大家介绍了关于Java基础篇之List集合的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • JAVA堆排序算法的讲解

    JAVA堆排序算法的讲解

    这篇文章主要介绍了JAVA堆排序算法的知识点,文中代码非常详细,配合上图片讲解,帮助大家更好的参考和学习,感兴趣的朋友可以了解下
    2020-06-06
  • java中利用List的subList方法实现对List分页(简单易学)

    java中利用List的subList方法实现对List分页(简单易学)

    本篇文章主要介绍了java中list数据拆分为sublist实现页面分页的简单代码,具有一定的参考价值,有需要的可以了解一下。
    2016-11-11
  • zookeeper概述图文详解

    zookeeper概述图文详解

    今天小编就为大家分享一篇关于Zookeeper概述图文详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • Retrofit+Rxjava实现文件上传和下载功能

    Retrofit+Rxjava实现文件上传和下载功能

    这篇文章主要介绍了Retrofit+Rxjava实现文件上传和下载功能,文中提到了单文件上传和多文件上传及相关参数的请求,需要的朋友参考下吧
    2017-11-11

最新评论