- 线程的历史 —— 一部对CPU压榨的血泪史
- 线程进程概念
- 单核CPU设定多线程是否有意义?
- 工作线程数是否设置的越大越好?
1、单线程人工切换(纸带机)
CPU利用效率低很多时间是等着人去换各种纸带
2、多进程批处理(多个任务批量执行)
但是如果其中一个任务等待的话也会导致其他任务跟着等待
3、多进程并行处理(把程序写在不同的内存位置上来回切换)
4、多线程(一个程序内部不同任务的来回切换)
5、纤程/协程(绿色线程,用户管理的【而不是OS管理的】线程)
首先看上面这个计算机的组成,
程序:
可执行文件。
进程:
首先双击我们电脑的一个程序比如QQ.exe,它会经过操作系统并把当前程序信息加载到内存中,内存中就有一个正在运行的QQ.exe,我们也可以再次点击QQ.exe登录另外的账号,所以一个程序是可以在内存里面放很多份的,在内存里面的每一份都可以称为一个进程。
进程就是操作系统分配资源的基本单位。(静态概念)
线程:
依然如上图,我们之前说点击QQ.exe,双击时我们的程序会进入到内存中变成一个进程,真正开始执行的时候程序是以线程为单位来执行的,操作系统会找到我们的主线程扔给CPU执行,然后如果主线程开启了其他的线程,CPU会在这些线程中来回切换。
概念上:线程就是CPU调度执行的基本单位(动态概念:多个线程共享同一个进程里的所有资源)
线程切换(底层角度理解):
ALU:计算单元
Registers:寄存器组(用于存放数据)
PC寄存器(存储到底执行到哪条指令了)
cache:缓存
所以当T1线程要运行的时候把T1的数据和指令放在CPU中,然后CPU计算单元对他进行计算,计算好了该做输出做输出,该做其他操作做其他操作。
但是根据操作系统调度算法的话,T1线程执行到一半把当前的CPU时间片用完了那么就会将T1的指令和数据放在缓存中,然后切换将T2的指令和数据放在CPU中继续做计算。如果T2的执行时间到了,就将T2的指令和数据放缓存里,再从缓存里面读取T1的数据和指令(当然这中间需要操作系统的调度切换【线程上下文切换】)。
有意义,比方说我的某一个在CPU执行的任务需要等待网络响应(等待的过程不消耗CPU资源),那么等待的这段时间如果设置了多线程的话,就可以切换到其他线程去执行任务,这样就可以充分利用CPU的资源。
CPU密集型:大量时间做计算。
CPU的IO密集型:大量时间在等待。
不是,这样导致CPU资源消耗在对线程的切换上面去了
public class Main {
//===================================================
private static double[] nums = new double[10_0000_000];
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();
}
}
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: " + (end - start) + " result = " + df.format(result));
}
//=======================================================
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: " + (end - start) + " result = " + df.format(result));
}
//===================================================================
private static void m3() throws Exception {
final int threadCount = 10000;
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=segmentCount*threadCount;i


