大家好,欢迎来到IT知识分享网。
线程的历史
- 之前的硬件,只有一个CPU
- 之前的OS,只运行一个进程
- 随着多核CPU的出现,人们开始追求对CPU效率的极致压榨
- 多线程的程序随之诞生,但随之诞生的,也是非常难以应对的各种并发bug
进程 线程
多线程–01–程序、进程、线程
纤程/协程:绿色线程,用户管理的(而不是OS管理的)线程
– 什么是进程:资源分配的基本单位(静态概念)
– 什么是线程:资源调度的基本单位(动态概念)
– 通俗说:一个程序中不同的执行路径
线程的调度,切换线程也存在性能损耗
区分:
- 程序:可执行文件,如xx.exe
- 进程:资源分配的最小单位。一个程序可能由多个进程组成,进程启动后,操作系统会在内存中给进程分配空间
- 线程:程序调度执行的最小单位,多个线程共享进程中的资源
- 单线程:只有一条执行路径,一个执行任务
- 多线程:有多条执行路径在同时运行,多个执行任务
一个java应用程序
一个java应用程序java.exe ,其实至少有三个线程:当然如果发生异常,会影响主线程
- main线程
- gc()垃圾回收线程
- 异常处理线程
一个多线程程序一个进程,会先运行主线程,然后运行期间,再进行线程的切换,抢夺时间片.
1. 单核CPU设定多线程是否有意义
回答这个问题需要考虑,我们的线程被用来执行什么样的任务? 常见的任务分为两种:
- CPU密集型任务
- IO密集型任务
CPU密集型任务(CPU-bound):
- 在一个任务中,主要做计算,CPU持续在运行,CPU利用率高,具有这种特点的任务称为CPU密集型任务。
IO密集型任务(IO-bound):
- 在一个任务中,大部分时间在进行I/O操作,由于I/O速度远远小于CPU,所以任务的大部分时间都在等待IO,CPU利用率低,具有这种特点的任务称为IO密集型任务。
因为存在线程等待的情况,所以在等待的时间,即是是单核cpu,也可以进行线程切换,让其他线程继续用cpu,这样提高了cpu的利用率.
2. 工作线程数是不是设置的越大越好?
案例:
- 测试设备:AMD r7 4700u , 8核
需求 :求一个亿的随机数据累加的和.
public class T01_MultiVSSingle_ContextSwitch {
//=====================一亿数据累积求和 ============================== private static double[] nums = new double[1_0000_0000]; private static Random r = new Random(); private static DecimalFormat df = new DecimalFormat("0.00"); static {
for (int i = 0; i < nums.length; i++) {
nums[i] = r.nextDouble(); } } public static void main(String[] args) throws Exception {
m1(); m2(); m3(); } }
单线程方法: m1
private static void m1() {
long start = System.currentTimeMillis(); double result = 0.0; for (int i = 0; i < nums.length; i++) {
result += nums[i]; } long end = System.currentTimeMillis(); System.out.println("m1: 1个线程" + (end - start) + " result = " + df.format(result)); }
2个线程 方法: m2
static double result1 = 0.0, result2 = 0.0, result = 0.0; private static void m2() throws Exception {
Thread t1 = new Thread(() -> {
for (int i = 0; i < nums.length / 2; i++) {
result1 += nums[i]; } }); Thread t2 = new Thread(() -> {
for (int i = nums.length / 2; i < nums.length; i++) {
result2 += nums[i]; } }); long start = System.currentTimeMillis(); t1.start(); t2.start(); t1.join(); t2.join(); result = result1 + result2; long end = System.currentTimeMillis(); System.out.println("m2: 2个线程" + (end - start) + " result = " + df.format(result)); }
32个线程 方法: m3
private static void m3() throws Exception {
final int threadCount = 32; Thread[] threads = new Thread[threadCount]; double[] results = new double[threadCount]; final int segmentCount = nums.length / threadCount; CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) {
int m = i; threads[i] = new Thread(() -> {
for (int j = m * segmentCount; j < (m + 1) * segmentCount && j < nums.length; j++) {
results[m] += nums[j]; } latch.countDown(); }); } double resultM3 = 0.0; long start = System.currentTimeMillis(); for (Thread t : threads) {
t.start(); } latch.await(); for (int i = 0; i < results.length; i++) {
resultM3 += results[i]; } long end = System.currentTimeMillis(); System.out.println("m3: 32个线程" + (end - start) + " result = " + df.format(result)); }
测试:
结论:
- 多线程通常情况下比单线程效率高
- 线程并不是越多越好,因为线程切换也需要耗费系统资源和时间.
3. 线程池中的线程数量设置多少合适?
根据任务类型推断:
当我们需要初始化一个线程池时,就要考虑我们的线程池被用来执行什么样的任务。
所以我们在设计线程池时,应先对执行的任务有个大体分类,然后根据类型进行设置。一般而言,两种任务的线程数设置如下:
CPU密集型任务:
- 线程个数为CPU核数。这几个线程可以并行执行,不存在线程切换到开销,提高了cpu的利用率的同时也减少了切换线程导致的性能损耗
IO密集型任务:
- 线程个数为CPU核数的两倍。到其中的线程在IO操作的时候,其他线程可以继续用cpu,提高了cpu的利用率
合适线程计算公式:
实际的w/c等待时间和计算时间的比率,需要实际生产压测出来.运用相关检测工具.
性能分析工具 profile
不管哪种公式和什么类型的任务,都需要实际生产压测数据为参考.
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/128769.html