在前面几篇文章中,波哥给小伙伴们讲解了什么是线程,以及创建线程的几种方法。这就有小伙伴问了,我们工作中用得最多的是线程池,波哥你能不能再给我们讲一讲线程池呀?既然小伙伴们提出需求了,波哥我就得满足大家了,今天我就为小伙伴们讲一讲线程池!
一. 线程池
1.什么是线程池
在面向对象编程中,创建和销毁对象是很耗费时间的,这是因为创建一个对象要获取较多的内存资源和其它资源。在Java中更是如此,虚拟机会试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。而提高服务程序效率的一个手段,就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁过程,这就是”池化资源”技术产生的原因。
而线程池,顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,我们需要的时候直接从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。
线程池的作用
线程池的存在,减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。另外我们可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累死机。
创建线程池的方式
线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景,总体来说线程池的创建可以分为以下两类:
第一个是通过 ThreadPoolExecutor手动创建线程池;
第二个是通过 Executors执行器来自动创建线程池。
3.1 ThreadPoolExecutor
ThreadPoolExecutor是最基础、也是最推荐的手动创建线程池的方式,它在创建时最多可以提供 7 个参数设置。ThreadPoolExecutor的使用示例如下:
// 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
// 执行任务
for (int i = 0; i < 10; i++) {
int index = i;
threadPool.execute(() -> {
System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
以上程序的执行结果如下图所示:
3.2 Executors
通过 Executors执行器自动创建线程池,我们有以下的几种实现方式:
Executors.newFixedThreadPool | 创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。 |
Executors.newCachedThreadPool | 创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。 |
Executors.newSingleThreadExecutor | 创建单个线程数的线程池,它可以保证先进先出的执行顺序。 |
Executors.newScheduledThreadPool | 创建一个可以执行延迟任务的线程池。 |
Executors.newSingleThreadScheduledExecutor | 创建一个单线程的可以执行延迟任务的线程池。 |
Executors.newWorkStealingPool | 创建一个抢占式执行的线程池(任务执行顺序是不确定的) |
以上就是执行器的几种实现方式,如果你想知道的更详细可以私信波哥哦,波哥可以为你更详细地解答!
二. 小结
通过波哥今天的讲解,不知道小伙伴们对线程池的作用是否有了一些了解,以及怎么去手动创建。另外在这里阿里巴巴的Java开发手册里,就强制他们的内部员工通过手动创建线程池,可见手动创建线程池的好处。
标签:波哥,销毁,Java,Executors,创建,小伙伴,简简单单,线程 From: https://blog.51cto.com/u_14319530/6965634