持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
启动1个线程
刚开始学习线程的时候,对于可以异步处理的任务,直接创建一个新的线程来处理。任务少没有什么问题。如代码所示:
public class ThreadTask {
public static void main(String[] arg){
Thread th = new Thread(new Task());
th.start();
}
static class Task implements Runnable {
public void run() {
System.out.println("Thread Name: " + Thread.currentThread().getName());
}
}
}
根据以上代码,发布一个任务并将其放入子线程中,然后启动子线程执行任务。整个过程很简单,执行结果就会打印出 “Thread Name:Thread-0”,即当前线程默认的名字。
但是随着任务增多的时候,比如可能有10个任务建立起10个子线程进行处理:
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Task());
thread.start();
}
打印结果你会发现顺序是无序的,不是按顺序打印出来。主要原因是运行的顺序取决于线程调度器所以会导致随机产生。
启动10000个线程
如果我们将子线程创建10000个,每个人任务都需要一定的耗时,那肯定产生很大的系统开销和资源浪费。
- 创建和销毁都需要时间,10000多个子线程反复创建销毁都会导致系统开销增大
- 占用内存和资源过多,太多线程占用,且它们线程切换也会导致系统不问题。
线程池
线程池就是来解决以上两个问题。线程池设置固定的线程数据量来保持工作状态并反复执行任务,这样就可以解决线程的创建开销问题。就是说,存在一些线程会一直在执行任务,一个任务执行完后再继续执行下一个任务,就完全不用担心每次都要创建一个线程才能执行任务。
同时,只需要设置固定的线程数来保持一直工作状态,就不用但是太多的线程占用太多的内存资源的问题。
线程池设计思路
线程池的设计思路就像是一个池子,有固定的管道,然后往管道里注入水到池子里。一吨水通过一个管道注入水完后,这个管道还可以继续用来注入水到池子里。
所以,需要固定的线程数保持工作状态,也保证资源不会被过度消耗。
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10000; i++) {
service.execute(new Task());
}
System.out.println(Thread.currentThread().getName());
}
从以上代码上看,创建了一个有5个线程的线程池,然后将10000个任务都放入到线程池里执行。从输出结果就可以看出一直都是这5个线程在反复的执行任务。
线程池优势
- 解决线程创建和销毁导致的系统开销问题。因为固定数量的线程可以反复使用,减小开销也能提升响应速度
- 避免资源使用不当。线程池根据配置和任务数量灵活控制线程数量,避免创建过多或过少的线程
- 线程池统一管理线程,方便使用。