【多线程】 线程池设多大才合理?CPU 密集型和 I/O 密集型的终极公式
在开始之前,让我们高喊我们的口号:
键盘敲烂,年薪百万!
我听说关注我的人未来都会暴富哦!
目录
键盘敲烂,年薪百万!
我听说关注我的人未来都会暴富哦!
引言
线程池
自定义线程池
代码实现
线程池多大合适?
什么是最大并行数?
怎么看电脑的最大并行数?
引言
一个故事,你有一个碗,吃完饭,摔了。下一顿,你得去买个碗,然后又吃饭,吃完又摔了。下一顿……
这很不方便,每次吃饭都要去买碗。于是解决方法就是买个碗柜,把碗放起来。
学到这里,你会发现,你需要线程就创建一个,而且一个线程完了就结束了。这样会极大的浪费操作系统的资源。所以我们准备一个容器存放线程,这个容器被称为线程池。
线程池
线程池核心(普通情况):给线程池提交一个任务的时候,线程池就创建一个线程去执行这个任务,执行完了就把线程还回线程池。下次再提交一个任务的时候,不需要再创建一个线程,而是用已经存在的线程去执行任务,再还回去。
特殊情况:
当提交第二个任务给线程池的时候,前一个线程正在执行第一个线程,那么这个时候线程池就会再创建一个线程去执行第二个任务,再还回线程池。以此类推,当345个任务要现成执行但是其他两个线程还在执行任务的时候,线程池会再创建345个线程来执行345任务,再还回线程池。
注意线程池是有上限的而且可以自己指定,这里如果指定线程池中只能创建3个线程,那45个任务只能等有空闲的线程后才可以执行。
这里的没有上限其实是假的,有上限,上限是整数的最大值,也就是21亿多个线程。但是呢,你的电脑创建不了那么多个线程就爆了。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class MyThreadPoolDemo {public static void main(String[] args) throws InterruptedException {/*public static ExecutorService newCachedThreadPool() 创建一个没有上限的线程池public static ExecutorService newFixedThreadPool (int nThreads) 创建有上限的线程池*///1.获取线程池对象ExecutorService pool1 = Executors.newFixedThreadPool(3);//2.提交任务pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());//3.销毁线程池//pool1.shutdown();}
}
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "---" + i);}}
}
自定义线程池
为什么要自定义?因为用java已经写好的明显并不够灵活。所以要学会自定义线程池。
一个故事理解:
一个饭店,有3名正式员工,3名临时员工。且这个饭店最大只能有6个员工。那么当人少的时候,3个正式员工和3个临时员工就可以了。但是当只有3个人来的时候,临时员工隔固定的时间段还没服务人就被辞退。当人大于6个人,饭店规定10个人之后就不要排队啦,明儿个再来!
具体解释:
过程:任务123分别创建123个核心线程去执行,规定了队伍长度为3,所以后面456任务在后面排队,任务78就被临时创建的线程45执行。什么时候创建临时线程?所以当任务数大于核心线程数和队伍长度且小于核心线程,队伍长度,临时线程数总和时,会创建临时线程。
但是当任务数超过总和时候,也就是核心线程在执行,排队排满了,而临时线程也在执行。这个时候就会引发 任务拒绝策略。
如果用第三种方式则会把线程4丢弃并把线城10拿进去排队。因为线程4最先排队,排队时间最长。
代码实现
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class MyThreadPoolDemo1 {public static void main(String[] args){/*ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);参数一:核心线程数量 不能小于0参数二:最大线程数 不能小于0,最大数量 >= 核心线程数量参数三:空闲线程最大存活时间 不能小于0参数四:时间单位 用TimeUnit指定参数五:任务队列 不能为null参数六:创建线程工厂 不能为null参数七:任务的拒绝策略 不能为null*/ThreadPoolExecutor pool = new ThreadPoolExecutor(3, //核心线程数量,能小于06, //最大线程数,不能小于0,最大数量 >= 核心线程数量60,//空闲线程最大存活时间TimeUnit.SECONDS,//时间单位new ArrayBlockingQueue<>(3),//任务队列Executors.defaultThreadFactory(),//创建线程工厂new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略);}
}
线程池多大合适?
什么是最大并行数?
以8核16线程为例
相当于有8个大脑,只能同时并行做8件事情。但是windows发明了超线程技术,让8个大脑影分身为16,可以同时并行做16件事情。这个同时并行可以做的最大数就是最大并行数。
怎么看电脑的最大并行数?
1.在此电脑点击右键,然后点击属性,在属性里找到设备管理器,再打开处理器,里面如果有16个那么最大并行数是16
2.有的电脑会隐藏起来一些,不告诉你最大并行数具体是多少。用idea执行下面的代码可以查看到真实的最大并行数。
public class MyThreadPoolDemo2 {public static void main(String[] args) {//向Java虚拟机返回可用处理器的数目int count = Runtime.getRuntime().availableProcessors();System.out.println(count);}
}
多大合适?
cpu密集型:计算多而读取少
I/O密集型运算:读取多而计算少,现在主流
cpu计算时间和等待时间怎么办呢?
可以用tread dump这个工具来测试。
今天的分享就到这里,欢迎在评论区交流
一起学习,一起进步!
如果你能关注我
那就是对我创作的最大鼓励啦!