关于多线程

并发编程

在计算机的操作系统中,我们了解到了进程管理,有了解到了cpu的特性,核心数和频率,在次之前我们所写的代码都是只用到了一个核心,此时无论你怎么优化代码,最多也只能使用到一个cpu的核心,把这个核心跑满了,其他的核心也是闲着,所以我们可以通过特殊的编写代码,把多个CPU的核心都能利用起来,这样的代码就称"并发编程",多进程编程也是一种典型的并发编程.

线程的由来

虽然多进程能够解决问题,但是随着对于效率要求越来越高,希望有更好的方式来进行并发编程,多进程编程,最大的问题就是太重了,创建进程/销毁进程,开销比较大(时间和空间),一旦需求场景需要频繁的创建销毁线程,开销就会非常明显了,最典型的就是服务器开发,针对每个发送请求的客户端,都创建一个独立的进程,由着个进程给客户端提供服务.为了解决进程开销的问题,发明了线程(Thread)

线程

线程可以理解成更轻量级的进程,也可以解决并发编程的问题,但是创建/销毁线程比进程开销更低,因此多线程编程成为更主流的并发编程方式,

所谓的进程,在系统中,是通过PCB结构体来描述的,也是通过链表的形式连接起来的,对于系统中,线程,同样也是通过PCB来描述的(Linux)

一个进程是一组PCB,一个线程是一个PCB,存在了包含关系,一个进程中至少有一个线程,也可以有多个线程,但不能没有线程,此时,每个线程都可以,独立到CPU上调度执行,线程是系统调度执行的基本单位 ,进程是系统进行资源分配的基本单位

一个可执行程序,运行的时候(双击),操作系统就会创建线程,给这个程序分配各种系统资源(CPU,内存,硬盘,网络带宽),同时也会在这个进程中,创建出这个一个或者多个线程,这些线程再去CPU上进行调度,

如果有多个线程在一个进程中,每个线程都会有自己的状态,优先级,记账信息,上下文,每个都会各自独立在CPU上调度执行,同一个进程中的这些线程,共用同一份系统资源,线程比进程更轻量,主要在于,创建线程省去了"分配资源"的过程,销毁线程也省去了"释放资源"的过程,一旦创建进程就会创建线程,系统就会分配资源,后续创建第二个第三个线程的时候,就不会再重新分配资源了.

适当提升线程数目,可以提高效率,关键是利用多核心,进行"并行执行",如果线程数目太多,超出了CPU的核心数,就会适得其反,线程之间相互抢占资源,由于多个线程,使用的是同一份资源(内存资源)->代码中定义的对象/变量,如果多个线程对同一个变量进行读写(尤其是写),就容易引起冲突,一旦发生冲突就可能程序出问题.

当一个进程中,有多个线程的时候,一旦某个线程抛出异常,这个时候,如果能够妥善处理,还好一旦处理不当,就可能导致进程崩溃,因此其他线程也会随之崩溃了.

所谓的"核心"是CPU的核心~硬件设备,而进程是系统管理的软件资源,进程也叫任务,任务需要交给核心来执行,每个进程中又可以包含多个线程

理解并行和并发

在微观角度看,多个核心,每个核心都可以执行一个线程,这些核心之间的执行过程是"同时执行的"并行,

一个核心,"分时复用",来切换多个线程,多个线程是一个接一个的执行,由于调度速度够快,宏观是看起来好像是同时执行,称为并发执行

进程线程的概念区别

1.进程包含线程,一个进程中至少有一个线程,也可以有多个线程,但不能没有线程

2.进程是系统分配资源的基本单位,线程是系统执行调度的基本单位

3.同一个进程里的线程之间,共用同一份系统资源(内存,硬盘,网络带宽等.....)尤其是"内存资源",就是代码中定义的对象/变量,编程中,多个线程可以共用同一份变量.

4.线程是当下实现并发编程的主流方式,通过多线程,就可以充分利用好多核心CPU,但是也不是线程数目越多,越好线程数目达到一定程度,把多个核心都充分利用好了之后,此时继续增加线程,无法在提高效率,甚至可能会影响效率(线程调度,也是有开销的)

5.多个线程之间,可能会相互影响,线程安全问题,一个线程抛出异常,也可能把其他线程一起带走

6.多个进程之间,一般不会相互影响,一个进程崩溃了,不会影响到其他进程(这一点也成为"进程的隔离性")

如何在Java代码中,编写多线程程序

线程,本身是操作系统提供的概念,操作系统提供API,供程序员使用,不同的操作系统,提供的API是不同的,而Java(JVM)把这些系统API封装好了,只需了解Java提供的这一套API就行

Thread(标准库),这个类就负责完成多线程的相关开发,此处这个类可以直接使用,不需要导入任何的包,在Java中,Java.lang默认自动导入

重新run方法

随后通过调用start()方法,就会在进程内部创建出一个新的线程,新的线程就会执行刚刚run的代码,

此时没有调用run方法,但是最终被执行了,这样的方法就成为回调函数,用户手动定义了,但是没有手动调用,最终这个方法被系统/库/框架调用了

这个方法是Thread的静态方法,通过类名.方法名进行调用

从编译角度理解:静态理解成编译过程中确定的,动态理解成运行过程中确定的,除了重写的方法,动态绑定,运行时确定,不去重写,也就是静态的

相关推荐
武子康12 分钟前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
若亦_Royi13 分钟前
C++ 的大括号的用法合集
开发语言·c++
资源补给站1 小时前
大恒相机开发(2)—Python软触发调用采集图像
开发语言·python·数码相机
豪宇刘1 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
m0_748247551 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
6.942 小时前
Scala学习记录 递归调用 练习
开发语言·学习·scala
FF在路上2 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人3 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言