java多线程学习(一)

目录:

            •  基础概念
            • CPU时间片轮转机制
            • 什么是进程和线程
            • 澄清并行和并发
            • 高并发编程的意义好处和注意事项

基础概念:

CPU核心数和线程数的关系:

        多核心:也指单芯片多处理器)(Chip Multiprocessors,简称CMP),CMP是由美国斯坦福大学提出的,其思想是将大规模并行处理器中的SMP(对称多处理器)集成到同一芯片内,各个处理器并行执行不同的进程。这种依靠多个CPU同时并行地运行程序是实现超高速计算的一个重要方向,称为并行处理。

        多线程:Simultaneous Multithreading.简称SMT.SMT可通过复制处理器上的结构状态,让同一个处理器上的多个线程同步执行并共享处理器的执行资源,可最大限度地实现宽发射、乱序的超标量处理,提高处理器运算部件的利用率,缓和由于数据相关或Cache未命中带来的访问内存延时。

        核心数、线程数的关系:目前主流CPU有双核、四核、六核等。增加核心数的目的就是为了增加线程数,因为操作系统是通过线程来执行任务的,一般情况下他们是1:1的关系,也就是说四核CPU一般拥有四个线程。但Intel引入超线程技术后,使核心数与线程数形成1:2的关系。

时间片轮转机制:

        我们平时在开发的时候,感觉并没有受CPU核心数的限制,想启动线程就启动线程,哪怕是在单核CPU上,这是为什么呢?这是因为操作系统提供了一种CPU时间片轮转机制。

        注意:这里需要澄清一点,我们并不是想启动多少线程就能启动多少线程,也就是说操作系统并不是对一个进程中的线程数没有限制,Linux系统一个进程中最大线程数的限制为1000个,Windows系统一个进程中最大线程数的限制是2000个。

        百度百科对CPU时间片轮转机制的解释:

        时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程序所要做的就是维护一张就绪进行列表,当进程用完它的时间片后,它被移到队列的末尾。

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

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

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

  时间片轮转机制的基本原理:

         在早期的时间片轮转算法中,系统将所有的就绪进程按先来先服务的原则,排成一个队列,每次调度时,把CPU分配给队首进程,并令其执行一个时间片,时间片的大小从几ms到几百ms不等。当执行的时间片用完时,由一个计时器发出时钟中断请求,调度程序便据此信号来停止该进程的执行,并将它送往就绪队列的队尾;然后,再把处理器分配给就绪队列中新的队首进程,同时也让他执行一个时间片。这样就可以保证就绪队列中的所有进程,在一定时间内均能获得一个时间片的处理器执行时间。

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

什么是进程和线程:

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

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

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

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

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

         线程无处不在

         任何一个程序都必须要创建线程,特别是java不管任何程序都必须启动一个main函数的主线程;java web开发里边的定时任务、定时器、JSP和Servlet、异步消息处理机制,远程方位接口RM等,任何一个监听事件,onClick的触发事件等都离不开线程和并发的知识。

澄清并行和并发

         我们举个例子来解释并行和并发的含义。

         如果有一条高速公路A上面并排有8条车道,那么最大的并行车辆就是8辆,此条高速公路并排行走的车辆小于等于8辆的时候,车辆就可以并行运行。CPU也是这个原理,一个CPU相当于一条高速公路A,核心数或者线程数就相当于并排可以通行的车道;而多个CPU就相当于并排有多条高速公路,而每个高速公路并排有多个车道。

         当谈及并发的时候一定要加上个单位时间,也就是说单位时间内并发量是多少?离开了单位时间是没有并发这一含义的。

         俗话说,一心不能二用,这对计算机也一样,原则上一个CPU只能分配给一个进程,以便运行这个进程。我们通常使用的计算机中只有一个CPU,也就是说只有一颗心,要让它一心多用同时运行多个进程,就必须使用并发技术。实现并发技术相当复杂,最容易理解的就是“时间片轮转机制”。

         综合来说:

         并发:指应用能够交替执行不同的任务,比如单CPU核心下执行多线程并非是同时执行多个任务,如果你开两个线程执行,就是在你几乎不可能察觉到的速度下不断去切换着两个任务,已达到 “同时执行效果”,其实并不是的,只是计算机的速度太快,我们无法察觉到而已。

         并行:指应用能够同时执行不同的任务,比如,吃饭的时候可以边吃饭边打电话,这两件事情可以同时执行。

         两者区别:一个是交替执行,一个是同时执行。

高并发变成的意义、好处和注意事项:

         由于多核多线程的CPU的诞生,多线程、高并发的编程越来越受重视和关注。多线程可以给程序带来如下好处。

       (1)充分利用CPU的资源

         从上面的CPU的介绍,可以看得出来,现在市面上没有CPU的内核不使用多线程并发机制的,特别是服务器还不止一个CPU,如果还是使用单线程的技术做思路,明显就out了。因为程序的基本调度单元是线程,并且一个线程也只能在一个CPU的一个核的一个线程跑,如果你是个i3的CPU的话,最差也是双核心4线程的运算能力,如果是一个线程的程序的话,那是要浪费3/4的CPU的性能,如果设计一个多线程的程序的话,那它就可以同时在多个CPU的多个核的多个线程上跑,可以充分的利用CPU,减少CPU的空闲时间,发挥它的运算能力,提高并发量。

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

         比如我们经常用的迅雷下载,都喜欢多开几个线程去下载,谁都不愿意用一个线程去下载,为什么呢?答案很简单,就是多个线程下载快啊。

         我们在做开发的时候更应该如此,特别是我们做互联网项目,网页的响应时间若是提升1s,如果流量大的话,就能增加不少转换量。做过高性能web前端调优的都知道,要将静态资源地址用两三个子域名去加载,为什么?因为每多一个子域名,浏览器在加载你的页面的时候就会多开几个线程去加载你的页面资源,提升网站的响应速度。

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

        例如我们在做Android开发的时候,主线程的UI展示部分是一块主代码程序部分,但是UI上的按钮用相应事件的处理程序就可以做个单独的模块程序拿出来。这样既增加了异步的操作,又使程序模块化,清晰化简单化。

        时下最流行的异步程序处理机制,正是多线程、并发程序最好的应用例子。

        多线程程序需要注意事项

       (1)线程之间的安全性

         我们知道,在同一个进程里面的多线程是资源共享的,也就是都可以访问同一个内存地址当中的一个变量。例如:若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

       (2)线程之间的死循环过程

         为了解决线程之间的安全性引入了java的锁机制,而一不小心就会产生java线程死锁的多线程问题,因为不同的线程都在等待那些根本不可能被释放的锁,从而导致所有的工作都无法完成。假设有两个线程,分别代表两个饥饿的人,他们必须共享刀叉并轮流吃饭。他们都需要获得两个锁:共享刀和共享叉的锁。假如线程A获得了刀,而线程B获得了叉。线程A就会进入阻塞状态来等待获得叉,而线程B则阻塞来等待线程A所拥有的刀。这只是人为设计的例子,但尽管在运行时很难揣测到,这类清苦却时常发生。

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

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

         某些系统资源是有限的,如文件描述符。多线程程序可能耗尽资源,因为每个线程都可能希望有这样一个资源。如果线程数相当大,或者某个资源的候选线程数远远超过了可用的资源数据库连接,它就从池中取出一个,使用以后再将它返回池中。资源池也称为资源库。

        

        至此,这篇文章就算完事了,这里全都是介绍的一些比较晦涩难懂的概念性的东西。在实际工作中可能不会用到这些但是,我们了解它总比不知道要好一些的。当然对于我来讲这篇文章记录知识的成分也是要远远大于理解知识的成分的。这里涉及到的一些概念的解释和案例也都是之前学习的时候老师给讲的或者从百度上看到的。

        非常感谢大家能够耐着性子看完我自己写的时候都觉得烦的概念。

        对Java线程感兴趣的同学可以继续关注下篇文章我将继续学习java中多线程的一些基础的使用。

 

相关文章阅读

java多线程学习(一)

java多线程学习二(线程的启动和终止)

java多线程学习三(线程间的共享和协作)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值