说到多线程,在我们现实生活中存在很多广泛的例子,就拿我本人做个典型案例吧。博主本人相貌出众,才艺双全,所以身边的女性资源可以说是非常丰富,与异性交往可谓是经验老道。在平时学习之余,可以和自己心仪的妹子一边聊骚,一边听音乐,兴起之时还可以哼几段小曲,不可谓不快活呀。在这个过程中,博主在同一个时间点可以同时处理很多件事情。其中和妹子聊骚是一个线程,听音乐是一个线程,哼曲也可以是一个线程,这便是多线程。
在更进一步地分析多线程的概念之前,我们还需要理清楚两个专有名词的区别,即进程与线程。
进程:在操作系统中运行的程序就是一个进程,比如快播、探探、陌陌等等。
线程:一个进程可以有多个线程,如我们看文艺动作片时,在看到女主肤白貌美、温润如玉的同时,还能听到女主魅惑的喘息声,并且为了增强用户体验度,片子里还会为我们显示中文字幕,这每一项都属于线程。
进程和线程的主要区别如下:
区别 | 进程 | 线程 | 描述 |
根本区别 | 作为操作系统资源分配的最小单位 | 程序执行的最小单位 | 计算机在执行程序时,会为程序创建相应的进程,进行资源分配时,是以进程为单位进行相应的分配。每个进程都有相应的线程,在执行程序时,实际上是执行相应的一系列线程。 |
开销 | 进程间的切换会有较大开销 | 线程执行开销小 | |
地址空间 | 进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段 | 线程没有独立的地址空间,同一进程的线程共享本进程的地址空间。 | |
资源拥有 | 进程之间的资源是独立的 | 同一进程内的线程共享本进程的资源 | |
执行过程 | 每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口 | 线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 | |
注:线程是处理机调度的基本单位,但是进程不是。由于程序执行的过程其实是执行具体的线程,那么处理机处理的也是程序相应的线程,所以处理机调度的基本单位是线程。很多多线程是模拟出来的,真正的多线程是指一个CPU有多个核心,或者一台服务器有多个CPU。如果是模拟出来的多线程,在同一个时间点,CPU只能执行一个代码,因为线程间切换速度很快,所以才会有同时执行的错觉。 |
在Java中,分为两类线程,即用户线程(User Thread)和守护线程(Daemon Thread)。我们日常业务开发中编写的逻辑代码运行之后,都属于用户线程的范畴。而守护线程,类似于操作系统里面的守护进程。由于Java语言机制是构建在JVM的基础之上,这一机制意味着Java平台是把操作系统的进程给屏蔽了。所以需要在JVM里面构造出对自己有利的机制,于是守护线程应运而生。
所谓的守护线程,指的是程序运行时在后台提供的一种通用服务的线程。比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
事实上,User Thread(用户线程)和Daemon Thread(守护线程)从本质上来说并没有什么区别,唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。
守护线程并非只有虚拟机内部可以提供,用户也可以手动将一个用户线程设定/转换为守护线程。
在Thread类中提供了一个setDaemon(true)方法来将一个普通的线程(用户线程)设置为守护线程。
程序运行时即使我们自己没有创建线程,后台也会存在多个线程,如GC(垃圾回收)线程、主线程等。
- 我们通常把main()称之为主线程,它是系统的入口,用于执行整个程序。
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统密切相关的,所以线程运行的先后顺序是不能人为干预的。
那么聊了这么多有关多线程的知识点,它究竟有什么作用呢?使用多线程又会带来哪些问题?我们在开发过程中又有哪些使用场景呢?博主总结多线程带来的好处主要有以下几点:
- 采用多线程的程序,拥有更快的响应速度。我们在用快播的时候,可以在欣赏一部文艺动作片的同时,下载其他的经典影片。这样当我们欣赏完一部影片,便可接着欣赏第二部已下载好的影片,观影过程更为流畅。
- 采用多线程可以极大地提高CPU的资源利用率。如果CPU在处理几项任务时,后面任务的执行必须等在前面的任务执行完,这个等待的过程是非常耗时耗资源的,那么有了多线程,前面的任务在占用大量处理资源时,CPU可以通过线程分配资源执行其他任务。
使用多线程常见的问题:
- 当多个线程对同一份资源进行操作时,会存在资源抢夺的问题,需要加入并发控制。
- 线程会带来额外的开销,如CPU调度时间、并发控制开销等。
- 每个线程在自身的工作内存交互,加载和存储主内存时如果控制不当会造成数据不一致。
多线程的应用场景:
- 图片的上传与下载:我们可以通过浏览器同时上传下载多张图片
- 电驴种子下载:我们下载种子时,电驴后台会同时开启多个线程,将一个种子分割成多块,通过多个节点共同完成对一个种子的下载。
- Web服务器在同一时刻接收多个用户的请求。
以上便是博主对于多线程概念的一个理解,由于博主水平有限,难免会存在疏漏。当你发现文中描述不准确或者错误的地方,欢迎留言指正。如果觉得博主写的不错的,可以点点关注,支持下博主。后续博主会分享个人学习积累下来的一些包括视频和书籍的技术资源,供大家免费学习使用。没有高深的知识,没有进阶的技巧,万丈高楼平地起!让我们一起在码农的职业生涯中共勉。