多线程(1)
通过多进程编程的方式,可以实现“并发编程”的效果。进程整体是一个比较“重”的概念,创建进程/销毁进程 开销比较大,尤其是频繁创建进程的时候(服务器开发)。所以为了解决问题,引入了线程(Thread),轻量级进程(创建 销毁的开销比较小)。
通过多进程编程的方式,可以实现“并发编程”的效果。
进程整体是一个比较“重”的概念,创建进程/销毁进程 开销比较大,尤其是频繁创建进程的时候(服务器开发)。所以为了解决问题,引入了线程(Thread),轻量级进程(创建 销毁的开销比较小)。
1. 进程和线程
每个进程,都相当于是一个要执行的任务
每个线程,也是一个要执行的任务(运行的一段代码指令)
1.1 进程包含线程
每个进程中,都会包含一个或多个线程(Windows的任务管理器,看不到进程内部的线程,需要借助一些其他的工具)->大任务和部分小任务
1.2 资源等
由上一篇博客“计算机的一些知识可知”:进程是操作系统资源分配的基本单位
例如:CPU、内存、硬盘资源(文件描述表)、网络带宽……
1)进程内部管辖的线程之间,会共享上述的内存、硬盘资源(文件描述表)、网络带宽……
补充:重量级的事情:进程创建需要申请资源,销毁进程需要释放资源
轻量级:对于线程来说,只有第一个线程创建(和进程一起创建)的时候申请资源,之后再创建线程不会涉及到申请资源的操作。只有所有的线程(进程)都销毁,才会真正释放资源
看到这,大家可能会有一个问题:一个进程内部的线程之间,是否会容易相互影响呢?
答:确实如此!!!也是多线程编程学习的最主要的难点:“线程安全问题”(比如:两个人喜欢上了同一个人,此时可能就会发生冲突)
这个我们之后再议~~
2)进程和进程之间,所涉及到的资源是各自独立的,彼此互不干扰(稳定性:稳定的运行环境 ->有没有想起操作系统那块的运行环境呀)
注意:对于“CPU”资源来说,很难使用“共享”这个词来描述(“CPU” 好比舞台,每个线程就是演员,每个演员(线程)都有去舞台(CPU)表演的机会)
线程在CPU上执行的一系列过程,和“进程调度”(线程调度)其实是一样的
3)线程是CPU上调度执行的基本单位(真正占用CPU执行的是线程):如果一个进程包含多个线程,此时,多个线程之间,各自去CPU上调度执行。比如 进程里面有线程 1,2,3 很有可能线程1去CPU核心1上执行,线程2去CPU核心2上执行,线程3去CPU核心3上执行(并行) 还有可能线程1,2,3在一个CPU的核心上来回切换(并发)也可能是线程1和线程2在一个CPU核心上来回切换,线程3在另一个核心上,和另一个进程来回切换…… 总之,线程是怎么调度执行的,程序员感知不到,也干预不了,它是由操作系统内部“调度器”自行完成的
4)每个线程都有一份这样的数据:调度相关、状态、优先级、记账信息、上下文(如果一个进程有10个线程,那么就有10份这样的数据,但是这10个数据共用同一个文件描述表和内存指针)
注意:线程数目如果太多,线程的调度开销也会非常明显,调度开销会拖慢程序的性能。、
2. 代码层面(Java)
线程,是操作系统提供的概念。
操作系统提供了一些api供程序员去使用
那么,什么是api呢???
api(Application Programming Interface 应用程序编程结果):大白话来讲:别人写了一些类/函数,你拿过来直接就能用。广义概念:操作系统会提供标准库、第三方库、其他的吧各种开源项目在工作中,隔壁的项目组给你提供的一些代码。
操作系统提供的原生线程api是C语言的,不同操作系统的线程api是不一样的。但是,Java对上述内容统一封装,Thread类(标准库中提供的类)
代码示例如下:

运行结果:

其中
start创建了一个新的线程,多了一个执行流(这个代买就可以“一心两用”,同时做两件事),所以上面的代码执行时,一共2个线程,分别是:主线程(main线程,当运行一个 Java 程序时,JVM 会自动创建一个主线程,用来执行 main 方法里的代码。在 main 方法里写的 Thread t = new MyThread(); 和 t.start(); ,都是在这个主线程里执行的)另一个是自定义线程(MyThread线程,t.start(); 这个方法会向操作系统申请创建一个新的线程,操作系统会让这个线程去执行 MyThread 类里的 run() 方法。所以 run() 方法里的 System.out.println("hello thread"); 是在这个新线程里执行的。)
之后,把上面的代码加工一下,示例如下:

作用:休眠,让当前的线程暂时放弃CPU,休息一会,时间过了之后,再执行(sleep是静态方法)
运行结果:

有时候main在前,有时候thread在前
从此结果,我们可以得出结论:多个线程的调度顺序是随机的。谁先执行,谁后执行,都有可能,无法预测,所以编写代码,就不能依赖这逻辑的执行顺序
相反情况(只有一个main线程(就是一个进程至少要包含的线程))
![]()
运行结果:

3. 借助工具,查看线程详细情况(Java)
1) 找到JDK的安装路径,之后再去“bin”里找到“jconsole.exe”
![]()
2)双击打开,如若打不开,右键以管理员身份运行,选中,点击连接

3)选中线程

4)解析界面
界面中下方左侧就是当前进程中的线程,
(和上面代码相关的),其他线程,都是JVM内置的线程
选中线程 在右侧就会看到详细信息,我们主要看
线程的调用栈,获取线程状态的时刻,线程里的代码执行到哪里了
OK啦,到此结束!!!
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)