线程之间的共享和协作
前言
在系列文章开始之前,我们首先了解一下线程的重要性:
线程
(Thread)是“进程”中某个单一顺序的控制流。也被称为轻量进程(lightweight
processes)。计算机科学术语,指运行中的程序的调度单位。所有的程序中,都有线程
一、进程和线程
1、进程是程序运行资源分配的最小单位
- 进程是操作系统进行资源分配的最小单位,其中包括:CPU、内存空间、磁盘IO 等、同一进程中的多条线程共享该进程中的全部系统资源,而进程和进程直接是相互独立的。进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
- 进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。显然程序是死的、静态的、进程是活动的、动态的。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们是处于运行状态下的操作系统本身,用户进程就是所有由你启动的进程。
2、线程是CPU 调度的最小单位,必须依赖于进程而存在
- 线程是进程的一个实体,是CPU 调度和分派的基本单位,它是比经常更小的、能够独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和堆栈),但是它可以与同一个进程的其他线程共享进程所拥有的全部资源。
3、线程无处不在
- 任何一个程序都必须创建线程,特别是Java 不管任何程序都必须启动一个main 函数的主线程;Java web 开发的定时任务、定时器、JSP 和 Servlet、异步消息处理机制,远程访问接口 RM 等,任何一个监听事件, onClick 的触发事件等都离不开线程和并发的知识。
二、CPU 核心数和线程数的关系
1、多核心
- 多核心:也指单芯片多处理器( Chip Multiprocessors,简称 CMP),CMP 是由美国斯坦福大学提出的,其思想是将大规模并行处理器中的SMP(对称处理器)集成到同一芯片内,各个处理器并行执行不同的进程。这种依靠多个CPU 同时并行的运行程序是实现超高速计算的一个重要方向,称为并行处理。
2、多线程
- 多线程:**Simultaneous Multithreading.简称 SMT.**让同一个处理器上的多个线程同步执行并共享处理器的执行资源。
3、核心数、线程数
- 核心数、线程数:目前主流 CPU 都是多核的。增加核心数目的就是为了增加线程数,因为操作系统是通过线程来执行任务的,一般情况下它们是1:1对应关系,也就是说四核 CPU 一般拥有四个线程。但 Intel 引入超线程技术后,使核心数与线程数形成了1:2 的关系。
三、CPU 时间片轮转机制
- 我们平时在开发的时候,感觉并没有受CPU 核心数的限制,想启动线程就启动线程,哪怕是在单核CPU 上,为什么?这是因为操作系统提供了一种CPU 时间片轮转机制。
- 时间片轮转调度是一种最古老、最简单、最公平且使用最广的一种算法,又称RR 调度。每个进程被分配一个时间段,称作它的时间片,即该进程运行运行的时间。
四、并行和并发
- 我们举个例子,如果有条高速公路A,上面有4条车道,那么最大并行车辆就是4辆,这条高速公路同时并排行走的车辆小与等于4的时候,车辆就可以并行行驶。CPU也是这个原理,一个CPU相当于一条高速公路,核心数或线程数就相当于并排可以通行的车辆;而多个CPU 就相当于有多条高速公路,而每个高速公路并排有多个车道。
- 当谈论并发的时候,一定要加个单位时间,也就是说单位时间内并发量是多少?离开单位时间其实是没有意义的。
- 俗话说一心不能二用,这对计算机也一样,原则上一个CPU只能分配给一个进程,以便运行这个进程。我们通常用的计算机只有一个CPU,也就是说只有一颗心,要让它一心多用同时运行多个进程,就必须使用并发技术。实现并发技术相当复杂,最容易理解的是“时间片轮转进程调度算法”。
1、并发
并发:
指应用能够交替执行不同的任务,比如单CPU核心下执行多线程并非是同时执行多个任何,如果你开两个线程执行,就是在你几乎不可察觉的速度不断去切换执行这两个任务,以达到“同时执行”效果,只是计算机的执行速度太快,我们无法察觉到而已。
2、并行
并行
:指应用能够同时执行不同的任务,例:吃饭的时候可以边吃饭边看电视,这两件事可以同时执行。
**
并发
和
并行
两者的区别就是:一个是交替执行,一个是同时执行**
五、高并发编程
- 由于多核CPU的诞生,多线程、高并发的编程越来越受重视和关注。
1、CPU 资源利用的充分
- 从上面CPU 的介绍,可以看出现在市面上没有CPU的内核不使用多线程并发机制的,特别是服务器还不止一个CPU。程序的基本调度单元是线程,一个线程也只能在一个一个CPU 的一个核的一个线程跑,如果你是个i3的CPU的话,最差也是双核心4线程的运算能力:如果是一个线程的话,那就会浪费钓3/4的CPU性能:如果设计一个多线程的话,那它就可以同时在多个CPU 的多个核的多个线程上跑,可以充分的利用CPU,减少CPU的空闲时间,发挥它的运算能力,提高并发量。
2、加快用户响应时间
- 比如我们经常使用的下载功能,很多朋友都会开通某一个会员,因为会员版本启用了多个线程去下载,谁都无法忍受一个线程去下,为什么呢?因为多线程下载快啊。
- 我们做程序开发的时候,网页速度提升1s,如果用户量大的话,就能增加不少转换量。我们经常浏览的网页中,浏览器在加载页面的时候,都会去多开几个线程去加载网络资源,提升网站的相应速度。多线程和高并发,在计算机中,无处不在。
3、使代码模块化、异步化、简单化
- 例如我们做一个电商项目,下订单和给用户发送短信、邮件就可以进行拆分,将给用户发送短信、邮件这两个步骤独立成两个单独的模块,交给其他线程去执行。这样即增加了异步的操作,提示了系统性能,又使程序模块化,清晰化和简单化。
六、多线程注意事项
1、线程之间的安全性
- 从前面的章节中我们都知道了,在同一个进程里面的多线程是资源共享的,也就是都可以访问同一个内存地址当中的一个变量。
例如:若每个线程中对全局变量、静态变量只读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
2、线程之间的死锁
- 为了解决线程之间的安全性引入了Java 锁的机制,而一不小心就会产生Java 线程死锁的多线程问题,因为不同的线程都在等待哪些根本不可能被释放的锁,从而导致所有的工作都无法完成。
假设有两个饥饿的人,他们必须共享刀叉并轮流吃饭,他们都需要获得两个锁,共享刀和共享叉。假如线程A获得了刀,而线程B获得了叉。线程A就会进入阻塞状态来等待获得叉,而线程B则主帅来等待线程A所拥有的刀。这只是人为设计的例子,单尽管在运行时很难探测到,这类情况却时常发生。
3、线程多了会将服务资源耗尽形成死机、当机
- 线程数太多有可能造成系统创建大量线程,而导致消耗完系统内存以及CPU的“过渡切换”,造成系统的死机,那么我们改如果解决这类问题呢?
某些系统资源是有限的,如文件描述。多线程程序可能耗尽资源,因为每个线程都可能希望有一个这样的资源。如果线程数相当大,或者某个资源的侯选线 程数远远超过了可用的资源数则最好使用资源池。一个最好的示例是数据库连接池。只要线程需要使用一个数据库连接,它就从池中取出一个,使用以后再将它返回池中。资源池也称为资源库。
- 多线程应用开发的注意事项很多,希望大家在日后的工作中可以慢慢体会它 的危险所在。
总结
🤩
🎉原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
👍
点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
🌟
收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️
评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!
版权归原作者 不爱学习的猪 所有, 如有侵权,请联系我们删除。