从零学Java 线程池

news2024/11/30 8:47:55

Java 线程池

文章目录

  • Java 线程池
    • 1 线程池概念
      • 1.1 现有问题
      • 1.2 线程池
    • 2 线程池原理
    • 3 如何使用线程池
      • 3.1 获取线程池
    • 4 创建线程的第四种方式

1 线程池概念

1.1 现有问题

  • 线程是宝贵的内存资源、单个线程约占1MB空间,过多分配易造成内存溢出。
  • 频繁的创建及销毁线程会增加虚拟机回收频率、资源开销,造成程序性能下降。

1.2 线程池

  • 线程容器,可设定线程分配的数量上限。
  • 将预先创建的线程对象存入池中,并重用线程池中的线程对象。
  • 避免频繁的创建和销毁。

2 线程池原理

在这里插入图片描述

将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程。

3 如何使用线程池

3.1 获取线程池

常用的线程池接口和类(所在包java.util.concurrent):

  • Executor:线程池的顶级接口。
    • execute(); 执行任务
  • ExecutorService:线程池接口,可通过submit(Runnable task) 提交任务代码。
    • shutdown() 关闭线程池
    • isTerminated() 判断线程池中任务和线程是否已经执行完毕。
    • submit() 提交任务
  • Executors工厂类:通过此类可以获得一个线程池。
    • newFixedThreadPool(int nThreads) 获取固定数量的线程池。
      参数:指定线程池中线程的数量。
    • newCachedThreadPool() 获得动态数量的线程池,如不够则创建新的,无上限。

eg:

//1 创建固定数量的线程池
ExecutorService es = Executors.newFixedThreadPool(4);
//2 创建动态数量的线程池
ExecutorService es = Executors.newCachedThreadPool();
public class TestExecutors {
    public static void main(String[] args) {
        //1.1 创建固定数量的线程池
        //ExecutorService es = Executors.newFixedThreadPool(4);
        //1.2 创建动态数量的线程池
        ExecutorService es = Executors.newCachedThreadPool();
        //2 添加任务
        Runnable ticket = new Runnable() {
            private int count = 1000;
            @Override
            public void run() {
                while (true) {
                    synchronized (this) {
                        if (count<=0) {
                            break;
                        }
                        System.out.println(
                                Thread.currentThread().getName()+"卖了第"+count+"张票"
                        );
                        count--;
                    }
                }
            }
        };
        for (int i = 0; i < 4; i++) {
            //提交任务
            es.submit(ticket);
        }
        //3 关闭线程池
        es.shutdown();
    }
}

eg:

//3 创建单线程线程池, 只有一个线程的线程池
public class TestSingThread {
    public static void main(String[] args) {
        //3 创建单线程线程池, 只有一个线程的线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"...");
                }
            });
        }
        es.shutdown();
    }
}

eg:

//4 创建调度线程池, 实现周期执行和延迟执行
public class TestScheduleThread {
    public static void main(String[] args) {
        //4 创建调度线程池, 实现周期执行和延迟执行
        //周期执行: 间隔指定时间执行一次, 不能关闭线程
        ScheduledExecutorService es = Executors.newScheduledThreadPool(1);
        es.scheduleAtFixedRate(new Runnable() {
            int num = 0;
            @Override
            public void run() {
                System.out.println(new Date()+"..."+num);
                num++;
                if (num == 10) {
                    es.shutdown();
                }
            }
        },0,1000, TimeUnit.MILLISECONDS);

        //延迟执行: 延迟一定时间执行
        es.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(new Date());
            }
        },3000, TimeUnit.MILLISECONDS);
        es.shutdown();
    }
}

eg:

//5 工作窃取线程池
public class TestWorkStealingPool {
    public static void main(String[] args) {
        //5 工作窃取线程池
        //5.1 工作窃取线程池中的都属于后台线程
        //5.2 每一个线程都有自己的双端队列, 队头和队尾都可以加入和删除元素
        //5.3 自己线程的队列中任务执行完后, 会去别的线程队列的队尾窃取一个任务执行
        //默认使用CPU内核个数作为线程个数
        ExecutorService es = Executors.newWorkStealingPool();
        for (int i = 0; i < 10; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"...");
                }
            });
        }
        es.shutdown();
        //阻止主线程结束
        while (!es.isTerminated()); //判断线程池中的任务和线程是否执行完毕
        System.out.println("执行完毕");
    }
}

4 创建线程的第四种方式

实现 Callable 接口, 重写 call() 方法

  • JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。
  • Callable具有泛型返回值、可以声明异常。

语法:

public interface Callable<V>{
	public V call() throws Exception;
}

Future接口

  • 概念:异步接收ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值。
  • 方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)

eg:

MyCallable:

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        System.out.println(Thread.currentThread().getName()+"开始计算...");
        for (int i = 1; i <= 100; i++) {
            sum+=i;
            Thread.sleep(100);
        }
        System.out.println(Thread.currentThread().getName()+"结束计算...");
        return sum;
    }
}

Test:

public class Test {
    public static void main(String[] args) throws Exception{
        //1 创建可调用对象
        MyCallable mc = new MyCallable();
        //2 创建线程池(单线程线程池)
        ExecutorService es = Executors.newSingleThreadExecutor();
        //3 提交任务
        //Future: 表示线程将要执行完毕的结果
        Future<Integer> future = es.submit(mc);
        //4 获取结果(阻塞方法, 直到线程池中的任务执行完毕才返回)
        System.out.println("结果是:"+future.get());
        //5 关闭线程池
        es.shutdown();
    }
}

课堂案例

eg:

需求:使用两个线程,并发计算1~50、51~100的和,再进行汇总统计。
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建动态线程池
        ExecutorService es = Executors.newCachedThreadPool();
        //添加任务1
        Future<Integer> f1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 1; i <= 50 ; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        //添加任务2
        Future<Integer> f2 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 51; i <= 100 ; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        //汇总
        System.out.println("结果为:"+(f1.get() + f2.get()));
        //关闭线程池
        es.shutdown();
    }
}

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

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

相关文章

将台式机变为服务器,服务器设置静态IP的方法

一.查看IP: 同时按winR&#xff0c;输入cmd&#xff0c;打开终端。输入 ifconfig查看IP地址 查看网关: route -n二、配置静态IP地址 进入root权限 sudo -i进入.yaml文件&#xff0c;开始配置静态IP地址 vim /etc/netplan /*.yaml文件地址是/etc/netplan/01-network-manager-…

【Leetcode】277.搜寻名人

一、题目 1、题目描述 假设你是一个专业的狗仔,参加了一个 n 人派对,其中每个人被从 0 到 n - 1 标号。在这个派对人群当中可能存在一位 “名人”。所谓 “名人” 的定义是:其他所有 n - 1 个人都认识他/她,而他/她并不认识其他任何人。 现在你想要确认这个 “名人” 是…

若依修改侧边栏

引用&#xff1a;https://blog.csdn.net/Sabrina_cc/article/details/125871591 子菜单选中后&#xff0c;文字和背景改变&#xff1a; .el-submenu__title i{color: #e8e8e8 !important;} #app .sidebar-container .theme-dark .nest-menu .el-submenu .is-active > .el-su…

软件测试BUG分析以及BUG定位

一般来说bug大多数存在于3个模块&#xff1a; 1、前台界面&#xff0c;包括界面的显示&#xff0c;兼容性&#xff0c;数据提交的判断&#xff0c;页面的跳转等等&#xff0c;这些bug基本都是一眼可见的&#xff0c;不太需要定位&#xff0c;当然也不排除一些特殊情况&#xf…

详解ISIS动态路由协议

华子目录 前言应用场景历史起源ISIS路由计算过程ISIS的地址结构ISIS路由器分类ISIS邻居关系的建立P2PMA ISIS中的DIS与OSPF中DR的对比链路状态信息的交互ISIS的最短路径优先算法&#xff08;SPF&#xff09;ISIS区域划分ISIS区域间路由访问原理ISIS与OSPF的不同ISIS与OSPF的术语…

Redis数据结构学习笔记

图文主要参考小林Coding的图解redis数据结构 redis为什么快 除了它是内存数据库&#xff0c;使得所有的操作都在内存上进⾏之外&#xff0c;还有⼀个重要因素&#xff0c;它实现的数据结构&#xff0c;使 得我们对数据进⾏增删查改操作时&#xff0c;Redis 能⾼效的处理。 数…

USB转SPI USB转IIC 串口转SPI串口转IIC SPI I2C模块

一款支持USB转SPI、USB转I2C、USB转GPIO、USB转PWM、USB转ADC的模块。提供上位机工具&#xff0c;开发协议。 资料下载&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1sw3RCMwjhrMO4qzUBq9bjA 提取码&#xff1a;qzjp 概述 串口转多协议模组为了客户调试一些功能…

快速上手的 AI 工具-文心一言

简介 最近正打得火热的AIGC概念&#xff0c;相信大家肯定也都多少接触到了&#xff0c;那么AIGC概念股到底是什么呢&#xff1f;我个人最近也看了一些平台如&#xff1a;文心一言、通义千问、讯飞星火、豆包等等&#xff01;各位朋友也千万不要错过啦&#xff0c;真是各有各的特…

opengauss-高斯数据库的安装部署及MySQL数据迁移实战.

目录 介绍 下载安装包 安装 1.设置SEMMNI 2.新建用户和用户组 3.下载安装包解压 4.安装数据库 5.修改配置 6.重启服务 数据库使用 gsql命令和常用sql 1.使用omm用户连接数据库-本地登陆无需输入密码&#xff1a; 2.查看用户信息 3.删除数据库 4.创建用户 5.创建…

【银行测试】银行项目,信用卡业务测试+常问面试(三)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行测试-信用卡业…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -投票帖子排行实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

LNMP环境下综合部署动态网站

目录 LNMP部署--nginx 搭建mysql数据库 安装mysql的过程&#xff1a; 部署PHP&#xff1a; ​编辑​编辑php的配置文件在哪 wordpress程序安装 LNMP部署--nginx 纯净--联网状态 环境变量中没有nginx 安装形式的选择&#xff1a; yum安装&#xff1a;自动下载安装包及…

C++ 最短路总结 朴素Dijkstra算法 || 模版题,求最短路

算法选择&#xff1a; 稠密图用邻接矩阵写&#xff0c;稀疏图用邻接表写。 朴素dijkstra&#xff1a; 给定一个 n 个点 m 条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c;所有边权均为正值。 请你求出 1 号点到 n 号点的最短距离&#xff0c;如果无法从 1 号点…

leaflet基本使用

leaflet&#xff1a;一个开源并且对移动端友好的交互式地图 JavaScript 库 中文文档&#xff1a;https://leafletjs.cn/reference.html 官网&#xff08;英文&#xff09;&#xff1a;https://iclient.supermap.io/examples/leaflet/examples.html#iServer 该项目基于vue3ts搭…

【CSP】2023年12月真题练习(更新到202312-2)

试题编号&#xff1a;202312-1试题名称&#xff1a;仓库规划时间限制&#xff1a;1.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 问题描述 西西艾弗岛上共有 n 个仓库&#xff0c;依次编号为 1⋯n。每个仓库均有一个 m 维向量的位置编码&#xff0c;用来表示仓库间的物…

[zabbix] zabbix监控其他

一、温习zabbix自定义监控 二、zabbix 自动发现与自动注册 2.1 zabbix 自动发现 //zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数…

各种版本对应关系:SpringCloudAlibaba——SpringCloud——SpringBoot——SpringFramework——JDK

SpringCloudAlibaba——SpringCloud——SpringBoot——SpringFramework——JDK 一般情况&#xff0c;在https://github.com/项目/wiki目录下有发布信息及对应的要求其他依赖的版本信息SpringCloudAlibaba——SpringCloud——SpringBootSpringBoot和SpringFramework的版本对应关…

新版K8s:v1.28拉取Harbor仓库镜像以及本地镜像(docker弃用改用containerd,纯纯踩坑)

这里写目录标题 一、项目概述二、环境三、项目样式Harborkuboard运行样式 四、核心点Harbor安装config.toml文件修改(containerd)ctr、nerdctl相关命令kuboard工作负载 五、总结 一、项目概述 使用Kuboard作为k8s集群的管理平台&#xff0c;Harbor作为镜像仓库&#xff0c;拉取…

LeetCode 41 缺失的第一个正数

题目描述 缺失的第一个正数 给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,0] 输出&#xff1a;3示例 2&#xff…

中科院自动化所:基于关系图深度强化学习的机器人多目标包围问题新算法

摘要&#xff1a;中科院自动化所蒲志强教授团队&#xff0c;提出一种基于关系图的深度强化学习方法&#xff0c;应用于多目标避碰包围(MECA)问题&#xff0c;使用NOKOV度量动作捕捉系统获取多机器人位置信息&#xff0c;验证了方法的有效性和适应性。研究成果在2022年ICRA大会发…