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

目录
  • 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四种线程池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详谈Java几种线程池类型介绍及使用方法

    一.线程池使用场景 •单个任务处理时间短 •将需处理的任务数量大 二.使用Java线程池好处 1.使用new Thread()创建线程的弊端: •每次通过new Thread()创建对象性能不佳. •线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom. •缺乏更多功能,如定时执行.定期执行.线程中断. 2.使用Java线程池的好处: •重用存在的线程,减少对象创建.消亡的开销,提升性能. •可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞

  • Java中四种线程池的使用示例详解

    在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及"过度切换". 本文详细的给大家介绍了关于Java中四种线程池的使用,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: FixedThreadPool 由Executors的newFixedThreadPool方法创建.它是一种线程数量固定的线程

  • Java ExecutorService四种线程池使用详解

    1.引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要的等到线程创建就能立即执行.第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.但是要做到合理的利用线程池,必须对其原理了如指掌. 2.线程池使用 Executors提供的四种线程 1.newCachedThreadPool创建一个可缓存线程池

  • 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } } ).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限

  • Java 线程池详解及实例代码

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收. 所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因. 例如Android中常见到的很多通用组件一般都离不开"池"的概念,如各种图片

  • java中通用的线程池实例代码

    复制代码 代码如下: package com.smart.frame.task.autoTask; import java.util.Collection;import java.util.Vector; /** * 任务分发器 */public class TaskManage extends Thread{    protected Vector<Runnable> tasks = new Vector<Runnable>();    protected boolean run

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

    目录 java预定义的哪四种线程池? 四种线程池有什么区别? 线程池有哪几个重要参数? 如何自定义线程池 总结 java预定义的哪四种线程池? newSingleThreadExexcutor:单线程数的线程池(核心线程数=最大线程数=1) newFixedThreadPool:固定线程数的线程池(核心线程数=最大线程数=自定义) newCacheThreadPool:可缓存的线程池(核心线程数=0,最大线程数=Integer.MAX_VALUE) newScheduledThreadPool:

  • java中常见的6种线程池示例详解

    之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如下 线程池名称 描述 FixedThreadPool 核心线程数与最大线程数相同 SingleThreadExecutor 一个线程的线程池 CachedThreadPool 核心线程为0,最大线程数为Integer. MAX_VALUE ScheduledThreadPool 指定核心线程数的定时

  • java简单实现多线程及线程池实例详解

    本文为大家分享了java多线程的简单实现及线程池实例,供大家参考,具体内容如下 一.多线程的两种实现方式 1.继承Thread类的多线程 /** * 继承Thread类的多线程简单实现 */ public class extThread extends Thread { public void run(){ for(int i=0;i<100;i++){ System.out.println(getName()+"-"+i); } } public static void mai

  • Android自带的四种线程池使用总结

    在Android开发中,如果我们要执行某个耗时任务,一般都会考虑开启一个线程去处理. 因为我们都知道一个线程run方法执行完毕后,才算真正结束,但是,这只是结束,并没有被回收,会一直闲置在那里,等待GC去回收,所以如果每执行一个任务,我们都new一个线程,那么在某些极端的场景下,是比较消耗内存的. 之前的内存优化的文章中,我讲过关于android中的池的概念,也就是复用的机制,那么对于线程也有个线程池. 这篇文章先简单介绍下Android中自带的四种线程池: 1 .newCachedThread

  • Spring boot注解@Async线程池实例详解

    这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从Spring3开始提供了@Async注解,该注解可以被标注在方法上,以便异步地调用该方法.调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行. 1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent

  • Python读取文件的四种方式的实例详解

    目录 学生数量特别少的情况 停车场空间不够时怎么办? 怎么加快执行效率? 怎么加快处理速度? 结语 故事背景:最近在处理Wikipedia的数据时发现由于数据量过大,之前的文件读取和数据处理方法几乎不可用,或耗时非常久.今天学校安排统一核酸检查,刚好和文件读取的过程非常相似.正好借此机会和大家一起从头梳理一下几种文件读取方法. 故事设定:现在学校要求对所有同学进行核酸采集,每位同学先在宿舍内等候防护人员(以下简称“大白”)叫号,叫到自己时去停车场排队等候大白对自己进行采集,采集完之后的样本由大白

  • jdk自带线程池实例详解

    二.简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力,但频繁的创建线程的开销是很大的,那么如何来减少这部分的开销了,那么就要考虑使用线程池了.线程池就是一个线程的容器,每次只执行额定数量的线程,线程池就是用来管理这些额定数量的线程. 三.涉及线程池的类结构图 其中供我们使用的,主要是ThreadPoolExecutor类. 四.如何创建线程池 我们创建线程池一般有以下几种方法: 1.使用Executors工厂类 Executor

  • Java四种线程池的使用详解

    Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,

随机推荐