【Java多线程】第一个线程池程序

Java多线程并发编程系列-00 线程池原理与自定义实现线程池 本文探讨了Java多线程并发编程中的线程池原理与实现。多线程的核心目的是充分利用CPU资源并发执行任务,但线程并非越多越好,需权衡创建/销毁开销、内存消耗及上下文切换成本。线程池通过固定数量的工作线程和任务队列(BlockingQueue)实现高效任务调度:任务提交到队列,空闲线程获取任务执行。针对计算型与IO型任务,线程数需动态调整(如CPU核数的1-2倍或更高)。文中还实现了一个简易线程池(FixedSizeThreadPool),包含任务队列、工作线程集合及关闭逻辑,并对比了阻塞(put/ta 阅读详情

线程池它就是一个池子(就像是养鱼的池子),可以养一定数量的鱼,可以重复使用!学习Java中的线程池,就是学习Java用了什么工具(API)和方法(设计模式)来搞出可以“养鱼的池子”。

本文作为入门级的线程池教程,主要介绍第一个线程池的一般写法,也就是“Hello,world”的水平,快速入门!


Table of Contents

什么是线程池

线程池体系

第一个线程池


什么是线程池

背景:

  1. 如果反复创建销毁线程,也会有一定的系统资源开销;
  2. 线程池,其实就是一个容纳多个线程的容器;Java初始时提供一定数量的、可重复使用的线程;
  3. 省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
  4. 此外,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。

为什么要使用线程池?

  1. 在java中,如果每个请求到达就创建一个新线程,开销是相当大的。
  2. 在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。
  3. 如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。
  4. 为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务。
  5. 线程池主要用来解决线程生命周期开销问题和资源不足问题。
  6. 通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。
  7. 这样,就可以立即为请求服务,使用应用程序响应更快。
  8. 另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。

《Java 并发编程的艺术》提到的来说一下使用线程池的好处:

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

注意:

  1. 程序一开始的时候,创建多个线程对象,存储到集合中;当需要线程的时候,从几回合中获取线程出来;
  2. 从JDK1.5开始,程序员不再需要自己开发线程池,而是使用内置线程池技术;

线程池体系

JDK给我们提供了Excutor框架来使用线程池,它是线程池的基础。Executor提供了一种将“任务提交”与“任务执行”分离开来的机制(解耦)。


第一个线程池

线程池的使用流程:

  1. 调用Executors类的静态方法创建线程池;
  2. 调用submit提交Runnable或Callable对象;
  3. 保存好返回的Future对象,以便得到结果或者取消任务;
  4. 当不想再提交任何任务时,调用shutdown

向线程池中提交Runnable接口的线程

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadDemo {
	public static void main(String[] args) {
		
		//第一步:调用Executors类的静态方法创建线程池;
		ExecutorService es = Executors.newFixedThreadPool(5); //创建一个固定大小的线程池
		
		//第二步-1:Runnable或Callable对象
		MyTask task = new MyTask();
		
		//第二步-2:提交Runnable或Callable对象到线程池中
		for(int i=0; i<10; i++) {
			es.submit(task); //连续提交10个线程到线程池中
		}
		es.shutdown();
	}
}
class MyTask implements Runnable {
	@Override
	public void run() {
		System.out.println("时间:"+System.currentTimeMillis()+";线程执行ID:"+
					Thread.currentThread().getName());
		try {
			Thread.sleep(1000); //休眠1s
		} catch(InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 程序输出:

  1. 时间:1585382666365;线程执行ID:pool-1-thread-1
  2. 时间:1585382666365;线程执行ID:pool-1-thread-4
  3. 时间:1585382666365;线程执行ID:pool-1-thread-5
  4. 时间:1585382666365;线程执行ID:pool-1-thread-2
  5. 时间:1585382666365;线程执行ID:pool-1-thread-3

 

  1. 时间:1585382667366;线程执行ID:pool-1-thread-5
  2. 时间:1585382667367;线程执行ID:pool-1-thread-1
  3. 时间:1585382667367;线程执行ID:pool-1-thread-2
  4. 时间:1585382667367;线程执行ID:pool-1-thread-3
  5. 时间:1585382667367;线程执行ID:pool-1-thread-4

分析:

  1. 根据输出:前5个任务和后5个任务的执行时间正好相差1s!
  2. 并且,前5个和后5个任务的线程ID都是完全一致的!说明前5个线程是同一个整体,后5个线程又是另一个整体!

 

向线程池中提交Callable接口的线程

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadDemo {
	public static void main(String[] args) {
		
		//第一步:调用Executors类的静态方法创建线程池;
		ExecutorService es = Executors.newFixedThreadPool(2); //创建一个固定大小的线程池
		
		//第二步-1:创建Runnable或Callable对象
		MyTask task = new MyTask();
		
		//第二步-2:提交Runnable或Callable对象到线程池中
		//第三步:用Future保存好每个任务,以便对任务的操作
		Future<String> re01 = es.submit(task);
		Future<String> re02 = es.submit(task);
		
		try {
			System.out.println(re01.get()+re02.get()); //对任务进行操作!
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		
		//第四步:关闭线程池
		es.shutdown();
	}
}

class MyTask implements Callable<String> {
	public String call() {
		String info = Thread.currentThread().getName();
		return info+"执行了....";
	}
}

Callable接口和Runnable接口一样,都是Java中多线程的实现方式。其中Callable接口实现的线程可以抛出异常,也可以有返回值,而Runnable接口实现的线程则不可以(不可抛异常,不可有返回值)!

 

 

 

Java多线程、线程池 fill:#333;color:#333;color:#333;fill:none;程序进程主线程子线程1子线程2。 阅读详情

相关推荐

可并行递归算法的递归多线程实现

关于如何实现在递归中实现多线程

java 线程池构建_java-为什么线程池仅创建一个线程?

我写了代码示例:class Test {public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor executorService = new ThreadPoolExecutor(0, 100,2L, TimeUnit.SECONDS,new LinkedBlockingQueue(...

weixin_42105169的博客 890

STM32CubeIDE(CUBE-MX hal库)----RTC时钟断电保持与时间校准实战

本文详细介绍了在STM32CubeIDE中使用CUBE-MX和HAL库实现RTC时钟断电保持与时间校准的实战方法。通过硬件配置、后备寄存器(BKP)操作及软件校准策略,确保嵌入式设备在断电后仍能保持准确时间,适用于智能电表、环境监测等物联网应用场景。

weixin_29189373的博客 216

mysql多线程使用一个链接_探索多线程使用同一个数据库connection的后果

在项目中看到有用到数据库的连接池,心里就思考着为什么需要数据库连接池,只用一个连接会造成什么影响?(只用一个connection)?1 猜想:jdbc的事务是基于connection的,如果多线程共用一个connection,会造成多线程之间的事务相互干扰。(connection.setAutoCommit(false);//connection.commit())2 于是就模仿以下场景来做一...

weixin_39633090的博客 1766

大数据应用技术实验报告一 Hadoop三种模式安装配置

JDK+Hadoop安装配置、单机模式配置 以下操作在SecureCRT里面完成 1.关闭防火墙 firewall-cmd --state 显示防火墙状态running/not running systemctl stop firewalld 临时关闭防火墙,每次开机重新开启防火墙 systemctl disable firewalld 禁止防火墙服务。 2.传输JDK和HADOOP压缩包 Sec...

Ruthless_Childe的博客 3090

如何找回mysql删除的表_mysql误删表如何恢复,恢复被删除表的步骤说明

小编寄语想必大家都知道,Oracle ACE李真旭(Roger)是国内最专业的Oracle 数据库恢复专家。但知识都是触类旁通,真正的专家,从来不会局限在一个方向上。今天分享的内容,是他在MySQL数据恢复上所做的尝试。本文主要分享在没有备份的情况下,MySQL数据库如何恢复被删除的表。包含两个主要的场景:1、drop table后的恢复2、truncate table后的恢复正文:我们都知道,M...

weixin_35725389的博客 6783

线程池原理及使用方法

1.背景 如果线程数量多,并且每个线程都只执行需要很短的执行时间的任务,这样频繁的创建线程、销毁线程,效率低下。若一个线程使用完毕后,并不销毁它,而是让他来执行别的任务,就可以使得线程重复使用,提高效率。 2.概念 线程池就是一种容器集合(ArrayList,HashSet,LinkedList<Thread>,HashMap) 3.底层原理 创建多个线程,保存到一个集合中,当我们想要使用线程的时候,就可以从集合中取出线程使用,Threa...

jl08133341的博客 1086

【Proteus仿真】用24C04与1602LCD设计的简易加密电子密码锁

【Proteus仿真】用24C04与1602LCD设计的简易加密电子密码锁

perseverance51博客 1121

深入理解线程和线程池(图文详解)

关于线程和线程池的学习,我们可以从以下几个方面入手:第一,什么是线程,线程和进程的区别是什么第二,线程中的基本概念,线程的生命周期第三,单线程和多线程第四,线程池的原理解析第五,常见的几种线程池的特点以及各自的应用场景一、线程,程序执行流的最小执行单位,是行程中的实际运作单位,经常容易和进程这个概念混淆。那么,线程和进程究竟有什么区别呢?首先,进程是一个动态的过程,是一个活动的实体。简单来说,一个...

weixin_40271838的博客 27万+

探索gtwr of mgtwr in python

代码】探索gtwr of GWmodel in python。

m0_46268055的博客 3388

【学习系列】SAP RAP 16:RAP应用部署集成至Fiori Launchpad 【On-Premise】

本文详细介绍了如何将开发完成的RAP应用部署到S4HANA 2023 On-Premise环境并集成到Fiori Launchpad的完整流程。主要内容包括:1)通过ADT工具创建Fiori项目并配置外部IDE(VSCode);2)使用npm命令部署应用到系统;3)通过事务代码创建语义对象、磁贴目录和目标映射;4)配置PFCG角色分配;5)补充了部署失败解决方案、翻译问题处理、自定义主题设置以及登录页面LOGO修改等内容。文章提供了step-by-step的操作指南,帮助开发者将预览模式的应用正式部署到生产

DeveloperMrMeng的博客 632

Java多线程案例之线程池

介绍线程池的原理和简单实现, 进一步提高并发编程的效率.

trong_ 的烂笔头 6123

基于 YOLOv26 的 PCB 板缺陷检测:工业级视觉实战

本文提出了一种基于YOLOv26的PCB板缺陷检测系统,通过深度学习技术实现对PCB板缺陷的自动化检测。系统能够识别短路、开路、焊点不良等8种常见缺陷,具有高精度、多类别分类和实时推理等优势。文章详细介绍了系统架构,包括数据采集、预处理、YOLOv26模型检测和后处理模块。在代码实现部分,给出了环境配置、数据预处理与增强的具体方法,使用Albumentations库进行图像增强处理。该系统为电子制造业提供了高效、准确的PCB质量检测解决方案,显著提升了检测效率和准确性。

一键难忘的博客 337

Java多线程、锁、线程池详解

通过本文的介绍,我们深入了解了Java中的多线程、锁机制、线程池的原理和应用。多线程可以提高程序的执行效率,但同时也带来了线程安全的问题。锁机制可以解决线程安全问题,而线程池则可以提高线程的复用率,减少线程创建和销毁的开销。理解这些概念的原理和应用可以帮助开发者编写高效、可靠的并发程序。希望本文能够帮助大家更好地理解和掌握Java中的多线程、锁和线程池,提升编程水平。

weixin_67825126的博客 2135

Python爬虫教程:抓取地方政府网站的公开文件与政策信息

Web爬虫是指一种自动化脚本,用于模拟人类浏览器访问网页、提取网页内容的数据抓取工具。发送请求到目标网页;获取网页内容;解析网页内容,提取所需数据;将数据保存或进一步处理。爬虫可以抓取各种形式的数据,如文本、图片、文件等。本教程将重点展示如何抓取地方政府网站上公开的政策文件、公告等信息。许多政府网站都会采取一定的反爬虫措施,防止大量数据被爬取。IP封锁:如果短时间内大量请求来自同一IP,可能会被封锁。验证码:一些网站会使用验证码来验证访问者是否为机器人。动态加载。

2201_76125261的博客 1981

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Java多线程案例——线程池

Java多线程案例——线程池

如风暖阳的博客 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

java多线程和线程池

目录 零、java线程理解 0.1 两种线程模型 0.1.1 用户级线程 ULT 0.1.2 内核级线程 KLT——JAVA虚拟机使用的线程模型(KLT) 0.2 java线程与系统内核线程 0.3 线程池的意义 0.4 线程 0.4.1线程五种状态 0.4.2 高并发下,线程池如何保证线程安全 0.4.3 多线程的使用场景 0.4.4 多线程的创建方式 0.4.4 多线程的停止 0.4.5控制多线程的运行顺序——join方法 一、线程池基本概念和使用示例 1.1 基本...

一直走,不要回头 8846

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

【Java篇】 1.CompletableFuture使用线程池进行异步多线程处理

多线程编程是提升程序性能和响应速度的关键手段之一, Java 提供了多种方式来实现并发处理,从早期的Thread类到后来的Executor框架,Java 8 引入了,结合线程池(ThreadPool)使用,不仅简化了多线程的编写,还大大提高了代码的可读性和可维护性。相比传统的多线程方式,ThreadPool的组合为开发者提供了更高层次的抽象,保留了灵活性,又降低了复杂性。

yanqingyu000的博客 5890

Java多线程——线程池

本文详细介绍了关于java线程池的相关知识点,主打一个详细面面俱到!

qq_51774011的博客 4783

线程池的使用:如何写出高效的多线程程序?

线程池是一种可以重复利用线程的技术,它可以减少线程的创建和销毁次数,从而提高程序的运行效率和响应速度。

程序羊的博客 2673

深入理解Java多线程与线程池:提升程序性能的利器

通过以上两种方式,可以实现Java中的多线程。选择合适的方式取决于具体的需求和项目架构,但一般来说,实现Runnable接口是更好的选择。通过使用线程池,可以更加灵活地管理和复用线程,避免了频繁创建和销毁线程的开销,提高了程序的性能和效率。根据实际需求选择合适的线程池类型可以更好地满足程序的需求。通过使用线程池,可以有效地管理和复用线程,避免了频繁创建和销毁线程的开销,提高了程序的性能和效率。合理地选择线程池的大小和类型,可以更好地满足程序的需求,避免系统资源被耗尽。减少线程创建和销毁的开销。

喔的嘛呀的博客 1335

java 多线程,线程池

java多线程, 线程池

一人码农 1268

Java【多线程】(5)线程池

哈喽大家好吖,今天来给大家继续进行多线程——线程池方面的学习,线程池在以后项目中也是关键的存在,废话不多说让我们开始吧。

2301_81073317的博客 3410

Java多线程——线程池使用

本文介绍一下Java多线程中线程池的使用方式。

qq_50867577的博客 1271

在java中如何设置多个线程池_Java多线程之线程池浅析

多线程是Java开发中的一个重要的领域,诚如我们所知道的,Java共有四种多线程的实现方式,第一种是集成Thread类,第二种是实现Runable接口(无返回值、不抛异常),第三种是实现Callable接口(有返回值、抛异常),第四种是通过线程池实现,本文主要介绍通过线程池的方式实现多线程。一、为什么要使用线程池、优势是什么?线程池的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在...

weixin_42212965的博客 4022
上一篇: 【Java多线程】多线程之间是如何实现通信的?
下一篇: 【JDBC】使用properties管理连接数据库的URL、用户名和密码
ALGO阿狗
博客等级 码龄9年 64粉丝 149原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值