最近小编看到大家都在讨论看了线程和线程池的对比,才知道池化技术到底有多牛相关的事情,对此呢小编也是非常的感应兴趣,那么这件事究竟是怎么发生的呢?具体又是怎么回事呢?下面就是小编搜索到的关于看了线程和线程池的对比,才知道池化技术到底有多牛事件的相关信息,我们一起来看一下吧!
【资料图】
情商高的人是能洞察并照顾到身边所有人的情绪,而好的文章应该是让所有人都能看懂。
尼采曾经说过:人们无法理解他没有经历过的事情。因此我会试着把技术文章写的尽量具象化一些,力求让所有人都能看懂,所以在正式开始之前,我们先从两个生活事例说起。
生活案例 1
早些年间,某宝双“11”突然爆火,然后无数个男男女女疯狂“剁手”,然而最痛苦的并不是“剁手”之后吃“灰”的日子,而是漫长而又揪心的等待快递小哥的日子。
为了缓解彼此的“痛苦”(快递公司的电话被打爆,用户等得不耐烦),快递公司后面就变“聪明”了,每当购物节将要来临之前,快递公司会预先准备好充足的人和车,以迎接扑面而来的订单。
至此,当我们再遇到各种购物节,就再也不用每天盯着手机煎熬的等待快递小哥了。
生活案例 2小美是一家公司的 HR,每年年初是小美最头疼的日子了。因为年初有大量的员工离职,因此小美需要一边办理离职员工的手续,一边疯狂的招人,除了这些工作之外,小美还要忍受来自各部门和大 BOSS 的间歇性催促,这些都让小美痛苦不已。
于是为了应对每年年初的这种囧境,小美也变聪明了,她每年年末的时候都会预先招聘一些员工,以备来年的不时之需。
自从用了这招之后(提前招人),小美从此过上了幸福的生活。
概念池化技术指的是提前准备一些资源,在需要时可以重复使用这些预先准备的资源。
也就是说池化技术有两个优点:
提前创建;
重复利用。
池化技术优点分析以 Java 中的对象创建来说,在对象创建时要经历以下步骤:
根据 new 标识符后面的参数,在常量池查找类的符号引用;
如果没找到符号应用(类并未加载),进行类的加载、解析、初始化等;
虚拟机为对象在堆中分配内存,并将分配的内存初始化为 0,针对对象头,建立相应的描述结构(耗时操作:需要查找堆中的空闲区域,修改内存分配状态等);
调用对象的初始化方法(耗时操作:用户的复杂的逻辑验证等操作,如IO、数值计算是否符合规定等)。
从上述的流程中可以看出,创建一个类需要经历复杂且耗时的操作,因此我们应该尽量复用已有的类,以确保程序的高效运行,当然如果能够提前创建这些类就再好不过了,而这些功能都可以用池化技术来实现。
池化技术常见应用常见的池化技术的使用有:线程池、内存池、数据库连接池、HttpClient 连接池等,下面分别来看。
1.线程池线程池的原理很简单,类似于操作系统中的缓冲区的概念。线程池中会先启动若干数量的线程,这些线程都处于睡眠状态。当客户端有一个新的请求时,就会唤醒线程池中的某一个睡眠的线程,让它来处理客户端的这个请求,当处理完这个请求之后,线程又处于睡眠的状态。
线程池能很高地提升程序的性能。比如有一个省级数据大集中的银行网络中心,高峰期每秒的客户端请求并发数超过100,如果为每个客户端请求创建一个新的线程的话,那耗费的 CPU 时间和内存都是十分惊人的,如果采用一个拥有 200 个线程的线程池,那将会节约大量的系统资源,使得更多的 CPU 时间和内存用来处理实际的商业应用,而不是频繁的线程创建和销毁。
import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线程池 vs 线程 性能对比
*/
public class ThreadPoolPerformance {
// 最大执行次数
public static final int maxCount = 1000;
public static void main(String[] args) throws InterruptedException {
// 线程测试代码
ThreadPerformanceTest();
// 线程池测试代码
ThreadPoolPerformanceTest();
}
/**
* 线程池性能测试
*/
private static void ThreadPoolPerformanceTest() throws InterruptedException {
// 开始时间
long stime = System.currentTimeMillis();
// 业务代码
ThreadPoolExecutor tp = new ThreadPoolExecutor(10, 10, 0,
TimeUnit.SECONDS, new LinkedBlockingDeque<>());
for (int i = 0; i < maxCount; i++) {
tp.execute(new PerformanceRunnable());
}
tp.shutdown();
tp.awaitTermination(1, TimeUnit.SECONDS); // 等待线程池执行完成
// 结束时间
long etime = System.currentTimeMillis();
// 计算执行时间
System.out.printf("线程池执行时长:%d 毫秒.", (etime - stime));
System.out.println();
}
/**
* 线程性能测试
*/
private static void ThreadPerformanceTest() {
// 开始时间
long stime = System.currentTimeMillis();
// 执行业务代码
for (int i = 0; i < maxCount; i++) {
Thread td = new Thread(new PerformanceRunnable());
td.start();
try {
td.join(); // 确保线程执行完成
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 结束时间
long etime = System.currentTimeMillis();
// 计算执行时间
System.out.printf("线程执行时长:%d 毫秒.", (etime - stime));
System.out.println();
}
// 业务执行类
static class PerformanceRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < maxCount; i++) {
long num = i * i + i;
}
}
}
}
总结从线程和线程池的测试结果来看,当我们使用池化技术时,程序的性能可以提升 10 倍。此测试结果并不代表池化技术的性能量化结果,因为测试结果受执行方法和循环次数的影响,但巨大的性能差异足以说明池化技术的优势所在。
无独有偶,阿里巴巴的《Java开发手册》中也强制规定「线程资源必须通过线程池提供,不允许在应用中自行显式创建线程」规定如下:
因此掌握并使用池化技术是一个合格程序员的标配,你还知道哪些常用的池化技术吗?欢迎评论区留言补充。