并发编程的基础知识篇

计算机与进程和线程之间的关系

  1.计算机中有一个重要的指标就是CPU,而CPU中又有一个重要的指标就和核心数。

  2.每当我们开启一个软件的时候,如QQ,微信(运行中的程序,被称为进程)。它们的运行必然是占据了CPU,而CPU就是进程运行的重要标准。(每个进程的运行都是占据着一个CPU的资源)

  3.而一个进程却又能同时做很多事情,被称为并行处理,其根本原因是,执行操作的并不是CPU,而是CPU中的内核(核心数代表有多少个内核,简单的理解为CPU是一个团队,而核心就是成员,进行做事的是成员而非团队)

 

什么是进程和线程(基于上面的说明)

  1.进程是程序运行资源分配的最小单位

    进程是操作系统进行资源分配的最小单位,其中资源包括:CPU、内存空间、磁盘 IO 等,同一进程中的多条线程共享该进程中的全部系统资源,而进程和进程之间是相互独立的。进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

    当你运行一个程序,你就启动了一个进程。显然,程序是死的、静态的,进程是活的、动态的。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运行状态下的操作系统本身,用户进程就是所有由你启动的进程。

 

  2.线程是 CPU 调度的最小单位,必须依赖于进程而存在

    线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的、能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

 

  3.线程无处不在

    任何一个程序都必须要创建线程,如 Java 不管任何程序都必须启动一个main 函数的主线程;

 

CPU 时间片轮转机制

  1.为什么会出现这种机制?

    按照正常逻辑,我们应该会认为一个进程占据一个CPU来运行程序,那么如果计算机只有一个CPU,是不是就只能运行一样东西呢?

    但是在实际上,我们查看计算机的任务管理器性能那块,会发现进程数和线程数都远远大于CPU数和核心数。

    正是由于这种 CPU 时 间片轮转机制,它分配给进程的CPU是带有时间限制的,时间到了就会回收,再发给其进程,故很多进程都能拥有CPU来运行程序,当没有获得时间片的时候就只能等待。

  

  2.CPU 时间片轮转机制原理解释

    时间片轮转调度是一种最古老、最简单、最公平且使用最广的算法,又称 RR调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。

    如果在时间片结束时进程还在运行,则 CPU 将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结来,则 CPU 当即进行切换。调度程序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。

    时间片轮转调度中唯一有趣的一点是时间片的长度。从一个进程切换到另一个进程是需要定时间的,包括保存和装入寄存器值及内存映像,更新各种表格和队列等。假如进程切( processwitch),有时称为上下文切换( context switch),需要 5ms, 再假设时间片设为 20ms,则在做完 20ms 有用的工作之后,CPU将花费 5ms 来进行进程切换。CPU 时间的 20%被浪费在了管理开销上了。

    为了提高 CPU 效率,我们可以将时间片设为 5000ms。这时浪费的时间只有0.1%。但考虑到在一个分时系统中,如果有 10 个交互用户几乎同时按下回车键, 将发生什么情况?假设所有其他进程都用足它们的时间片的话,最后一个不幸的进程不得不等待 5s 才获得运行机会。多数用户无法忍受一条简短命令要 5 才能做出响应,同样的问题在一台支持多道程序的个人计算机上也会发生。

    结论可以归结如下:

      时间片设得太短会导致过多的进程切换,降低了 CPU 效率:而设得太长又可能引起对短的交互请求的响应变差。将时间片设为 100ms 通常是一个比较合理的折衷。

 

    在 CPU 死机的情况下,其实大家不难发现当运行一个程序的时候把 CPU 给弄到了 100%再不重启电脑的情况下,其实我们还是有机会把它 KⅢ掉的,我想也正是因为这种机制的缘故。

 

并行和并发之间的区别

  所谓并行:指应用能够同时执行不同的任务

  所谓并发:指应用能够交替执行不同的任务(可以理解为 时间片轮转进程调度算法 ,这样更直观)

  汇总:两者区别:一个是交替执行,一个是同时执行.(注:谈论并发的时候一定要加个单位时间,也就是说单位时间内并发量是多少?离开了单位时间其实是没有意义的。)

 

高并发编程的意义、好处

  (1)充分利用 CPU 的资源

    因为程序的基本调度单元是线程,并且一个线程也只能在一个 CPU的一个核的一个线程跑,如果你是个 i3 的 CPU 的话,最差也是双核心 4 线程的运算能力,如果是一个线程的程序的话,那是要浪费 3/4 的 CPU 性能。

    如果设计一个多线程的程序的话,那它就可以同时在多个 CPU 的多个核的多个线程上跑,可以充分地利用 CPU,减少 CPU 的空闲时间,发挥它的运算能力,提高并发量。

 

  (2)加快响应用户的时间

    如实现电商系统,下订单和给用户发送短信、邮件这些步骤都是在一个业务逻辑里面的。如果用一个线程来执行,每一步之间的执行时间就会是总的执行时间,如果采用多个线程来执行,那么它们之间最长的那个步骤的执行时间就会是总的执行时间。因为在最长时间的步骤中,其他的步骤都完成了,这样下来可以节省很多响应时间,而用户也就不需要等待那么长时间了。

 

  (3)可以使你的代码模块化,异步化,简单化

    如实现电商系统,下订单和给用户发送短信、邮件就可以进行拆分,将给用户发送短信、邮件这两个步骤独立为单独的模块,并交给其他线程去执行。这样既增加了异步的操作,提升了系统性能,又使程序模块化,清晰化和简单化。

 

多线程程序需要注意事项

  (1)线程之间的安全性

    1.要知道在同一个进程里面的多线程是资源共享的,也就是都可以访问同一个内存地址当中的一个变量。(如全局共享变量)

    2.如:若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的。

    3.若有多个线程同时执行写操作,一般都需要考虑线程同步(加锁隔离),否则就可能影响线程安全。

 

  (2)线程之间的死锁(可查看 死锁详解

    为了解决线程之间的安全性引入了 Java 的锁机制,而一不小心就会产生 Java线程死锁的多线程问题,因为不同的线程都在等待那些根本不可能被释放的锁,从而导致所有的工作都无法完成。

    示例:如A和B两个线程需要资源a和b,A获取资源顺序为a再拿b,B获取资源顺序为b再拿a。

      因此会出现A拿到了a,B拿到了b,由于锁的原因,双方都拿不到下一步的资源而导致等待,进而空耗资源的情况,从而影响到整个系统的其他线程。

    

  (3)线程太多了会将服务器资源耗尽形成死机当机

    线程数太多有可能造成系统创建大量线程而导致消耗完系统内存以及 CPU的“过渡切换”,造成系统的死机,那么我们该如何解决这类问题呢?

    某些系统资源是有限的,如文件描述符。多线程程序可能耗尽资源,因为每个线程都可能希望有一个这样的资源。如果线程数相当大,或者某个资源的侯选线程数远远超过了可用的资源数则最好使用资源池

posted @ 2022-09-17 02:39  忧愁的chafry  阅读(44)  评论(0编辑  收藏  举报