java线程池理解及底层

news2024/9/28 11:14:27

并发线程池示例(两个示例程序分别用线程 及java自带程池执行一样的程序查看时间):

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Long start = System.currentTimeMillis();
        final Random random = new Random();
        final List<Integer> list = new ArrayList<>();
        //循环10万次 创建了 10万零一个线程
        for (int i = 0; i < 100000; i++) {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    list.add(random.nextInt());
                }
            };
            thread.start();
            thread.join();
        }
        //用8秒
        System.out.println("花费的时间"+(System.currentTimeMillis()-start));
        System.out.println("list大小"+list.size());
    }
}


public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        Long start =System.currentTimeMillis();
        final Random random = new Random();
        final List<Integer> list = new ArrayList<>();
        //java自带的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //这里也创建了10w个对象,但是这里只创建了两个线程
        for (int i = 0; i < 100000; i++) {
            executorService.execute(
                    new Runnable() {
                        @Override
                        public void run() {
                            list.add(random.nextInt());
                        }
                    }
            );
        }
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
        //用25毫秒
        System.out.println("花费时间:"+(System.currentTimeMillis()-start));
        System.out.println("list大小:"+list.size());
    }
}

        这里为什么创建了10w的对象 只创建了两个线程,因为都是调用的run方法,run()和start方式启动是不一样的;

示例:

public class ThreadDemo extends Thread{
    private String name;
    public ThreadDemo(String name){
        this.name=name;
    }

    @Override
    public void run() {
        System.out.println(name);
    }

    public static void main(String[] args) {
        //方法调用
//        new ThreadDemo("eric").run();
        //线程启动
        new ThreadDemo("lily").start();
        //线程的名字不一样
    }

如果调用run方法是调用自己重写的run方法,只有一个线程,debug快照可对比:

 

 start()启动是调用另一个线程

 

 线程池底层很多是run()方法的调用,这也是为什么线程池相对而言更快一点的原因。

从1.5开始的,针对java线程池的工具类

 并不是只要用线程池就一定是最快的,例子如下:

ublic class ThreadPoolTest2 {
    //一般不推荐用java自带工具类写线程池
    public static void main(String[] args) {
        //快
        ExecutorService executorService1 = Executors.newCachedThreadPool();
        //比上面的慢  一共用10个线程去执行那100个任务
        ExecutorService executorService2 = Executors.newFixedThreadPool(10);
        //最慢的     线程池用一个线程去执行这100个任务
        ExecutorService executorService3 = Executors.newSingleThreadExecutor();
        //执行了100个项目 每个项目需要执行三秒,分别用这三种线程池去执行
        for (int i = 0; i < 100; i++) {
//            executorService1.execute(new MyTask(i));
//            executorService2.execute(new MyTask(i));
            executorService3.execute(new MyTask(i));
        }
    }
}

/**
 * 项目
 */
class MyTask implements Runnable {
    int i;
    public MyTask(int i) {
        this.i = i;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"做的第"+i+"个项目");
        //业务逻辑执行3秒
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 MAX_VALUE:

核心线程数:0,任务进来后是没有核心线程去做的

会用临时线程去做,目前最大线程数是:MAX_VALUE

任务进来后,由于没有核心线程,所以会先放到工作队列里面workQueue中,这里用的SynchronousQueue<Runnable> 同步队列(典型的生产消费方式),当放了一个任务进来后,就需要消费掉,否则后面的任务没法放进来,相当于只能存一个对象进来,存一个对象进来后,就需要有临时线程去进行消费,执行此任务。

当把任务执行时间注释掉,

 就会出现线程复用的情况

由于项目执行很快,一个线程可以做多个任务。这种线程池相对于其他线程池容易造成CPU100%问题,因为最大线程数没有限制 

 这里用的核心线程数为10,最大线程数也为10(意味着没有临时线程),临时线程存活时间为0,用了无界队列(队列的结构特点是FIFO),这个队列无限大可以接收N个任务放里面

 只有10个线程去处理任务

 

 只有1个核心线程,最大线程也是1,无界队列,始终只有一个线程去执行任务。

 是否需要用线程池,及用哪种线程池,取决于我们项目执行时间的长短

一般都用自定义线程池,可自行规定参数

//自定义线程池 队列指定容量10 额外多出的临时线程生命周期为1秒
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,
        0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10));

 

 执行任务的时候,有自己的执行逻辑,30个任务后,拒绝了,最后线程执行队列里面剩余的任务。这里是执行优先级,优先核心、非核心 获取任务执行,都没有 才从队列里面获取任务去进行执行

 Executor顶级接口只有一个execute方法,没有返回值,

 AbstractExecutorService 实现了接口

 

 submit方法调用了execute执行方法,同时有返回值 这也是跟execute方法的一个区别

我们自定义的线程池ThreadPoolExecutor继承自AbstractExecutorService

底层执行原理:  

 

 线程池处理流程:

 自带拒绝策略:

 

ThreadPoolExecutor内部有实现4个拒绝策略:

(1)CallerRunsPolicy,由调用execute方法提交任务的线程来执行这个任务;

(2)AbortPolicy,抛出异常RejectedExecutionException拒绝提交任务;

(3)DiscardPolicy,直接抛弃任务,不做任何处理;

(4)DiscardOldestPolicy,去除任务队列中的第一个任务(最旧的),重新提交;

一般都是自定义拒绝策略。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一个java短网址转换项目,亲测可用

亲测可用 项目介绍的比较详细,我就不复制粘贴了,直接看项目介绍即可 启动项目后先拿注册账户,登陆,然后创建应用,然后新增短域即可

科研实验室设计基本知识SICOLAB

科研专用实验区 dedicated laboratory area 有特定环境要求&#xff08;如恒温、恒湿、洁净、无菌、防振、防辐射、防电磁干扰等&#xff09;或以精密、大型、特殊实验装置为主&#xff08;如电子显微镜、高精度天平、谱仪等&#xff09;的实验区。 标准单元 standard unit 具…

组内每隔 5 行加一个分隔线

【问题】 I have grouped the data on the column “state” and set the pagebreak option to “Always Excluding First” so that I can see the data related to a particular state in a separate page. I’m trying to add a horizontal line after every 5 rows in th…

如何选择语音短信通知平台?语音短信通知平台接入教程

语音通知主要是指通过语音短信平台的语音电话给用户发送消息通知的方式&#xff0c;在很多行业都得到广泛的应用。语音通知短信平台主要用于系统告警通知、入住提醒、民生公告报警等场景中。语音通知短信平台的主要优势&#xff1a;减少人员的重复劳动&#xff0c;提升人员的工…

进程间通信之管道

文章目录什么是进程间通信为什么进程要通信通信的本质是什么什么是管道匿名管道命名管道总结什么是进程间通信 首先&#xff0c;通过前面的学习。我们知道了进程是具有独立性的&#xff0c;绝大多数情况下&#xff0c;一个进程挂掉了并不会影响另外一个进程。进程和进程之间拥…

点云 3D 分割 - SqueezeSegV2(ICRA 2019)

点云 3D 分割 - SqueezeSegV2&#xff08;ICRA 2019&#xff09;摘要1. 引言2. 相关工作3. 改进模型结构A. 上下文聚合模块B. 焦点损失C. 其他改进4. 领域适应训练A. GTA-LiDAR数据集B. 学习强度渲染C. 测地相关对齐D. 渐进域校准5. 实验A. 实验设置B. 改进的模型结构C. 域适配…

SpringBoot与MyBatistaPlus通过jtds集成SQLServer

背景 通过 SpringBoot 与 MyBatis Plus 实现与 SQLServer 的集成&#xff0c; CRUD 。 SpringBoot集成SQLServer 新建 SpringBoot 项目&#xff0c;常规操作&#xff0c;在依赖中选择 Web , Lombok , SQLServer &#xff0c;附加 MyBatis Plus 。 核心依赖 <dependency&…

IQ基带信号

一段 IQ基带信号的解释 射频信号可以下变频得到较窄带宽的基带IQ信号&#xff0c;反之&#xff0c;较窄带的基带IQ信号可以上变频成射频信号发送。在IQ信号层面可以进行多样的调制、解调处理。 那么&#xff0c;什么是IQ信号&#xff1f; IQ信号描述推导 设调制在载波频率…

Latex基本结构和中文处理

目录源文件结构例子代码运行结果Latex中文处理办法在vscode中进行latex中文环境的编写设置步骤如下&#xff1a;在texstudio中进行中文编写步骤例子代码知识点带有序号的数学表达式用newcommand创建新的命令运行结果查看相关帮助文档ctex宏包中文版latex快速入门手册源文件结构…

力扣sql入门篇(四)

力扣sql入门篇(四) 1 丢失信息的雇员 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT e.employee_id employee_id FROM Employees e LEFT JOIN Salaries s ON e.employee_ids.employee_id WHERE s.employee_id is null UNION SELECT s.employ…

微服务框架支持

事务上下文目录概述需求&#xff1a;设计思路实现思路分析1.Seata 的事务上下文由 RootContext 来管理。2.应用可以通过 RootContext 的 API 接口来获取当前运行时的全局事务 XID。3.应用是否运行在一个全局事务的上下文中&#xff0c;就是通过 RootContext 是否绑定 XID 来判定…

机器学习--房屋销售的探索性数据分析

目录 一、导入相关包 二、读取数据 三、做简单的处理 总结 一、导入相关包 numpy&#xff1a;python中做数据分析常用的包&#xff1b; pandas&#xff1a;也是用于数据分析&#xff0c;擅长处理表&#xff0c;数据没那么大要放入内存中&#xff0c;这将是首选&#xff1…

client-go源码学习(二):Reflector、DeltaFIFO

本文基于Kubernetes v1.22.4版本进行源码学习&#xff0c;对应的client-go版本为v0.22.4 3、Informer机制 在Kubernetes系统中&#xff0c;组件之间通过HTTP协议进行通信&#xff0c;在不依赖任何中间件的情况下需要保证消息的实时性、可靠性、顺序性等。那么Kubernetes是如何…

重装操作系统win10+重装sqlserver+数据库可视化工具

sqlserver安装以及使用 一、重装操作系统 操作系统win10镜像 原因&#xff1a;sqlserver无数次失败让我放弃原来操作系统。 重装操作系统三步骤 1>下载大白菜一键装机工具 2>有一个u盘&#xff0c;8G以上存储空间 3>win10系统镜像 详细讲解&#xff1a; win10系统镜…

管道和重定向

1.重定向 1.输出重定向 > 一般用于在控制台上为了避免看到过多冗余的代码代码操作&#xff0c;所以将正确和错误的结果信息写到文件夹中 标准输出 1> 1>> [rootiZ2zef4rb5ixg6sieztgsdZ /]# cat /etc/passwd > file.txt //将/etc/passwd中输出的结果打印…

ElasticSearch6.x版本概念介绍及Kibana操作的增删改查常用API

文章目录一、概念介绍1.接近实时(NRT Near Real Time )2.索引(index)3.类型(type)4.映射(mapping)5.文档(document)6.概念关系图二、Kibana的基本操作1.创建dangdang索引并创建product类型2.删除dangdang索引3.创建id为1的文档记录4.查询id为1的文档记录5.删除id为1的文档记录6…

【2022年终总结】:小伙子还需努力呀~

文章目录前言第一次遇见CSDN我的收获我的迷茫我的展望前言 有一段时间没写博客了&#xff0c;具体什么原因呢&#xff1f;先买个关子&#xff0c;埋在下面的文字里。 眨眼时间&#xff0c;在CSDN待了快一年了&#xff0c;这一年的时间里有收获有感动&#xff0c;当然&#xff0…

IO多路复用【学习笔记】

1.用户空间和内核空间 虚拟内存被操作系统划分成两块&#xff1a;内核空间和用户空间&#xff0c;内核空间是内核代码运行的地方&#xff0c;用户空间是用户程序代码运行的地方。当进程运行在内核空间时就处于内核态&#xff0c;当进程运行在用户空间时就处于用户态。 为了安全…

elasticsearch在linux环境安装使用过程遇到的问题

es在linux环境安装遇到问题 1、启动失败日志 ERROR: [1] bootstrap checks failed [1]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be con…

MCU-51:单片机之AT24C02学习

目录一、存储器介绍1.1 RAM1.2 ROM二、AT24C022.1 AT24C02介绍2.2 引脚及应用电路2.3 内部结构框图三、I2C总线3.1 I2C总线介绍3.2 I2C电路规范3.3 I2C时序结构3.4 I2C数据帧3.5 AT24C02数据帧四、代码演示4.1 AT24C02数据存储4.2 秒表(定时器扫描按键数码管)注意&#xff1a;一…