多线程系列文章
线程池
什么是线程池
所谓线程池,其实可以理解为是一个存放线程的池子,我们首先创建线程到线程池中,在需要用到该线程时,再从线程池中取出相应的线程进行加载,使用完毕以后,再归还线程到线程池中;但实际上,线程池更加倾向于是一种解决问题的思想,而并非在内存中有一块线程池的空间;
为什么要引入线程池
还记得在进程部分,我们谈到明明进程就可以实现并发编程,为何又要引入线程呢?
我们说,进程本身是相当重量的,创建进程需要申请资源,销毁进程需要释放资源,在频繁的进程创建销毁的过程中,成本是极高的,因此我们引入了线程;
线程通过对同一组资源的共用,在一定程度对进程的成本问题做出了优化,但是仅仅这样的优化是不够的,线程进行频繁的创建和销毁同样带来了问题;因此我们引入了线程池的概念,创建线程到线程池,使用完毕以后归还线程到线程池,不再通过系统来创建和销毁,由于从线程池中的操作属于纯用户态操作,而通过系统创建的操作属于内核态操作,因此可以有效提高效率。
java中的线程池
java中提供了一个静态工厂来创建不同的线程池,即Executors工厂类;
public class Demo1 {
public static void main(String[] args) {
//创建出固定包含10个线程的线程池
ExecutorService threadPool= Executors.newFixedThreadPool(10);
//返回值类型:ExecutorService
for (int i=0;i<100;i++){
//注册任务到线程池中
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello threadPool");
}
});
}
}
}
Executors类中提供了多种创建线程池的方式,上面代码演示的是创建固定线程数的线程池,还有线程数目动态增长的线程池的创建(newCachedThreadPool:)、只包含单个线程的线程池的创建(newSingleThreadExecutor)等,可以在不同的应用场景中自发选择,这里不做过多描述;
模拟实现一个线程池
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
//创建一个线程池类
class MyThreadPool{
//以阻塞队列来存放要完成的任务
private BlockingQueue<Runnable> queue=new LinkedBlockingQueue<>();
//往线程池中插入任务
public void submit(Runnable runnable){
try {
//把线程放入队列
queue.put(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//设置线程池中的线程个数 n
public MyThreadPool(int n){
//创建线程来完成执行任务的工作
for (int i=0;i<n;i++){
Thread t=new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
try {
//从队列取出线程来执行
Runnable runnable=queue.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
}
public class Demo2 {
public static void main(String[] args) {
MyThreadPool myThreadPool=new MyThreadPool(10);
for (int i=0;i<100;i++){
myThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("MyThreadPool");
}
});
}
}
}
这里模拟实现的是一个固定了线程数的线程池,这种线程池的特点是:
如果线程数没有达到线程池的固定数量,每提交一个任务,线程池内就创建一个新线程,直到线程达到线程池的固定数量;当线程池的大小达到了固定数量时,就会保持不变,直到有线程因为执行异常而结束,线程池中就会补充一个新的线程;
一般这样一种线程池适用于处理CPU密集型的任务;
使用线程池,可以有效降低Java线程的创建成本,线程主要解决了以下2个问题:
线程池带来的好处
- 提升性能:线程池可以独立负责线程的创建、维护及分配,将任务交给线程池去调度,线程池会尽可能使用空闲的线程去执行任务,对已经创建的线程进行复用,明显提升性能;
- 线程管理:每个Java线程池都会对线程的一些基本信息进行统计,像完成的任务数量或空闲时间等,可以对线程进行有效的管理,从而实现对任务的高效调度;
在许多企业的编程规范中,线程必须通过线程池提供,为了减少系统资源的开销,由此也见线程池的优越。
over!