一、概念
- 进程与线程
进程是操作系统进行资源分配管理和调度的单元,比如我们打开QQ,运行的QQ就是一个进程。
线程是进程的一个子集,线程是CPU进行调度和执行的单元。
一个进程可以包含一个线程(单线程的进程),也可以包含多个线程(多线程的进程)。 - 多核与多线程
在单核时代,也可以实现多线程,同一时间内,各个(同一或者不同)线程争夺CPU时间片。
在多核时代,各个进程及其线程可以在不同CPU内核上执行。多核为多线程并行执行提供了可能。 - 并发、并行与串行
串行:各个线程排队等待CPU的执行。
并发:指的是不同线程同时争夺一个CPU内核的时间片,这种状态就是并发。
并行:不同线程在不同CPU内核上同时执行,彼此相互不影响。
二、效率与时间
我们通常说并发能够提升执行效率,觉得并发就跟提升效率有关。
现在假设有一种情况,一个多线程的进程,在被分配在固定的CPU内核上执行,各个线程虽然在并发,但是CPU一会执行这个线程,一会儿执行那个线程,不断切换,这个跟CPU先执行完A线程的任务,再执行完B线程的任务,接着C线程的任务…并没有什么时间效率上的提升,更有甚者,CPU在不断切换线程时,也需要不断切换线程上下文,切换上下文会带来时间和资源开销,与其这样并发,还不如串行呢?
所以,这里有个理解误区,提升效率不等于缩短执行时间。
假使打开QQ,我们一边时而回复聊天,时而逛空间,如果,采用串行的方式,我们就得等聊天完成后,才能正常逛空间;而如果采用多线程的方式,CPU不断切换线程执行,宏观上我们就会觉得聊天和逛空间完全可以同时进行。这就是提升了效率。
另一点理解误区,并发能缩短总执行时间。
一个多线程的进程运行在多核CPU上,它到底是并行还是并发,这个我不知道,因为CPU调度一会儿把线程分配在这个CPU内核上,一会儿把CPU分配在那个CPU内核上,各个线程可能在同一CPU内核,也可能在不同CPU内核。当在不同的CPU内核执行时,这两个线程就是并行;当两个CPU内核同时争夺同一个CPU内核的时间片时,这两个线程就是并发。
而并行才能缩短总的执行时间。
三、多线程的进程不一定会使用多核并行处理
验证如下:
本机电脑4核8G。
如下案例,开启4个线程每个线程依次打印100万次。
package org.example.demo5;public class ThreadTest {private static final int num = 1000 * 1000;public static void main(String[] args) throws InterruptedException {//因为Visual VM找到java进程需要时间,所以这里让主线程先睡一会儿,//等待Visual VM找到进程再开始启动各子进程打印Thread.sleep(50000); new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程1").start();new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程2").start();new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程3").start();new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程4").start();}
}
通过使用Visual VM查看线程状态,可知各个线程是在同一个CPU上并发执行的。
修改执行次数,改成2000万次
package org.example.demo5;public class ThreadTest {private static final int num = 20000 * 1000;public static void main(String[] args) throws InterruptedException {Thread.sleep(50000);new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程1").start();new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程2").start();new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程3").start();new Thread(()->{for (int i = 0; i < num; i++) {System.out.println(i);}},"线程4").start();}
}
通过下图可知,4个线程同时存在并发核并行的情况。
根据以上案例可知:
一个多线程的进程在多核处理器上,可能是以并发的方式运行,也可能是以并发+并行的方式运行。
参考:
https://www.cnblogs.com/jiading/articles/12454398.html
https://blog.csdn.net/qq_33290787/article/details/51790605
Visual VM工具的使用
https://www.cnblogs.com/xifengxiaoma/p/9402497.html