Java高并发与多线程(一)-----概念

其实以前一直想专门写一篇,单独说一说Java的多线程与高并发,可是一直以来,都没有想到可以用什么比较有趣的表现形式去表达出来,并且网上充斥着不少相似的博客,有好的又很差的,有简介的有繁琐的,因此也一直没写。 java

可是想了想既然以前有这个想法,并且也已经很久没有写过博客了,索性仍是写一写,尽可能写的有意思一点。 web

   

另:以前的高并发&性能优化没有来得及往下写,实在是由于里面的东西太过于复杂,且最近正好换了工做,确实没有那么多时间去研究,如今写东西仍是但愿能多写点有用的,而不是书本照搬当笔记用,固然能力有限,写烂了,你们谅解一二,略过不看便可。 算法

   

固然第一篇,咱们依旧从概念开始,因此第一部分还是概念。 数据库

   

【并发与并行】 缓存

从题目名词开始讲。 性能优化

  • 并发

并发,顾名思义,一块儿出发;微信

在你吃饭的时候,来了一个电话,若是你能够先接电话,而后再继续把饭吃完,这个叫并发;网络

可是若是你只能等饭吃完才能够去接电话,叫非并发(串行)。多线程

因此,并发指的是处理多任务的能力,当你只能一件事情一件事情串行执行任务的时候,就是不支持并发的,当你能够多件事情一块儿执行的时候(轮替或者其余方式),就是支持并发的。架构

   

  • 并行

仍是举上面那个例子,当你吃饭的时候,来了一个电话,你边吃饭边接电话,这叫并行;

并行指的就是同时运行;支持并行的基础就是多线程。

   

【同步和异步】

同步和异步的概念通常用于方法

  • 同步  

    当一个方法开始执行,必须等这个方法执行结束,才能够往下执行,咱们叫作同步。

    同步主要用于上下有递进关系的代码,特色是有序,串行执行,逻辑简单,可是执行效率较低。

  • 异步     

    当一个方法开始执行,咱们没必要等这个方法执行结束,直接执行后面的内容,咱们叫作异步。

    (能够认为只是进行了一个消息的传递,调用后会当即返回)

    异步在java里面主要使用线程(包括一些封装类也是如此)实现,特色是执行效率高,可是逻辑相对复杂,容易出问题

   

【什么是高并发】

有果必有因,通俗来说,多线程能够认为是高并发的一种表现形式或者解决方案,因此在讲多线程以前,咱们先讲高并发。

高并发,指的是一个系统,在短期内,收到大量操做请求的状况。

这种状况,通常而言主要发生在web系统中,好比:京东双十一,微博明星传出绯闻,12306春运抢票等等。

 

很容易理解的东西咱们不过多的做诠释,如下几项,是高并发的经常使用指标:

  • 响应时间Response Time

    系统对请求做出的响应时间(一个请求从请求发出到请求结束的时间)

  • 吞吐量Throughput

    单位时间内处理的请求数量

  • 每秒查询率QPSQuery Per Second

    每秒响应请求数。(其实与吞吐量指向同一个指标)

  • 并发用户数

    同时承载正常使用系统功能的用户数量。

   

这里须要注意的是,咱们常常会将高并发和多线程放在一块儿讲,可是他们之间并不能划等号,多线程只是高并发在应用代码层面的一种解决方案,然而通常状况下,高并发还须要系统架构,硬件设施,网络等多方面的调优协助完成。

   

【雪崩效应】

雪崩效应,本来出如今密码学中,后来引伸入高并发场景的一个概念。

在密码学中,雪崩效应(Avalanche effect)指加密算法(尤为是块密码和加密散列函数)的一种理想属性。

雪崩效应是指当输入发生最微小的改变(例如,反转一个二进制位)时,也会致使输出的剧变(如,输出中一半的二进制位发生反转)。

   

服务雪崩效应是一种因"服务提供者的不可用"(缘由)致使"服务调用者不可用"(结果),并将不可用逐渐放大的现象。

服务雪崩的过程能够分为三个阶段:

  1. 服务提供者不可用;
  2. 重试加大请求流量;
  3. 服务调用者不可用;

   

------如何避免

横向扩充服务------如今咱们能够利用不少工具来保证服务不会挂掉,而后流量比较大的时候,能够横向扩充服务来保证业务的流畅。

限流(下个部分会讲)

熔断(下个部分会讲)

   

【高并发的四大利器】

对于软件系统而言,通常会有四大策略去保证应用的高并发:

  • 缓存(cache)

    把经常使用数据存储到能够快速获取的区域(缓存区),以便重复利用,提升效率。

例如:从内存中读取数据时,先将经常使用的数据存放到缓存区,硬盘直接从缓存区读取。

   

在这地地方咱们要注意

咱们平时所说的缓冲(buffer),和缓存不是同一回事,缓冲指的是在数据流转过程当中,不一样层次数据速度不一致时,利用缓冲区来缓解上下层之间速度问题,增长速度。

例如:将数据写入到内存时,先写入缓冲区,内存则直接从缓冲区中读取写入,减小IO次数,增长速度,下降对磁盘的损耗。

不过他们本质上都是为了提升效率

   

  • 降级

    当服务出现问题或影响到核心流程时,须要暂时屏蔽掉,待高峰事后或问题解决后再打开;

   

  • 限流

    限流是高并发里面最重要也是最复杂的方法,当不可降级场景出现时,须要采用限流限制该场景的并发请求,有损服务而不是不服务。

经过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则能够拒绝服务、排队或等待、降级

    • 超过阈值时策略

         定向到错误页或告知没有资源

         返回兜底数据或默认数据,如商品详情页库存默认有货

    • 常见限流场景

        线程池

数据库链接池

并发请求数

接口调用速率

MQ的消费速率

    • 常见限流算法

        令牌桶:一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌,请求获取令牌,令牌不足时拒绝请求。

漏桶:流入速率过快,超过桶的容量,拒绝请求。

计数器(简单粗暴):当请求超过计数时,拒绝请求。

   

  • 熔断

    降级每每表明系统功能部分不可用,熔断表明的是彻底不可用。
    降级通常是客户端处理熔断是在服务端处理的
    服务熔断通常是指软件系统中,因为某些缘由使得服务出现了过载现象,为防止形成整个系统故障,从而采用的一种保护措施,因此不少地方把熔断亦称为过载保护

   

【进程】

首先咱们看一下百度百科的解释:

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操做系统结构的基础。

在早期面向进程设计的计算机结构中,进程是程序的基本执行实体

在当代面向线程设计的计算机结构中,进程是线程的容器

程序是指令、数据及其组织形式的描述,进程是程序的实体。

   

其实用大白话讲,进程其实就是指在系统中正在运行的一个应用程序

好比:咱们电脑中运行的QQ,微信,LOL,都是一个进程。

   

进程主要有如下几个特性:

  • 独立性

    进程是系统中独立存在的实体,它拥有本身独立的资源和本身私有的地址空间。

    进程之间不能够直接访问资源和地址空间。

  • 动态性

    程序(App)是一个静态的指令集和,进程是一个正在执行中的指令集合,进程拥有本身的生命周期和不一样的生命形态。

  • 并发性

    多个进程能够在单个处理器上并发执行,不会相互受到影响。(主要是依赖于线程和时间片)

一个进程里面能够由单个或者多个线程协同 完成任务。

   

【什么是多线程】

  • 首先,什么是线程?

    教科书说法,线程是操做系统可以进行运算调度的最小单元

一个进程能够有多个线程,可是一个线程只有一个父进程;

线程能够拥有本身的堆栈,程序计数器以及局部变量,可是不拥有系统资源。

   

其实呢,学过操做系统你们都知道,其实对于单核单CPU而言,同时是只能运行一个任务的,也就是说,同时只能跑一个线程;

若是我们的CPU只能线性执行,就是当你运行一个线程的时候,这个线程可能要等待网络,IO等相关的资源,这个时候CPU只能等待,这样CPU强大的运算能力就没有获得发挥,因此,产生了一个时间片的概念;

    • 时间片

        CPU给每一个线程分配了一部分时间去运行,虽然CPU同时只能运行一个线程,可是咱们进行线程的快速切换以后,能够模拟出一个CPU同时运行多个线程的场景(其实主要仍是CPU太快了),这样的话能够充分利用CPU计算速度快的优点。(对于时间片,有不少种不一样的算法,有兴趣能够百度,这里不讲)

        在引入时间片之后,我们一块CPU就能够同时跑多个线程了。

   

因此什么是多线程呢?

多线程指的是,在单个程序(或者进程)里面,能够运行多个不一样的线程,执行不一样的任务,最终完成整个程序的运行逻辑。
 

这里须要注意的是,线程是进程的子集,不一样的进程使用不一样的内存空间,而全部的线程共享一片相同的内存空间

别把它和栈内存搞混,每一个线程都拥有单独的栈内存用来存储本地数据

   

【线程的状态】

其实下面这些随便找个教科书或者网上的教程都有,属于废话,可是为了概念的完整性,仍是把它们贴在下面:

只须要关注带颜色的内容

  • 新建状态(New)

    线程对象被建立后,就进入了新建状态。

   

  • 就绪状态(Runnable)

    也被称为"可执行状态"。线程对象被建立后,其它线程调用了该对象的start()方法,从而来启动该线程。

   

  • 运行状态(Running)

    线程获取CPU权限进行执行。须要注意的是,线程只能从就绪状态进入到运行状态

   

  • 阻塞状态(Blocked)

    阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。
    直到线程进入就绪状态,才有机会转到运行状态。
      - 等待阻塞

    经过调用线程的wait()方法,让线程等待某工做的完成。

      - 同步阻塞

    线程在获取synchronized同步锁失败(由于锁被其它线程所占用),它会进入同步阻塞状态。

      - 其余阻塞

    经过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。

   

  • 死亡状态(Dead)

    线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

   

【多线程三要素】

  •  原子性

    即一个不可再被分割的颗粒。

在Java中原子性指的是一个或多个操做要么所有执行成功要么所有执行失败

经典场景:张三向李四转帐,扣钱和入钱操做,要么所有完成,要么所有完不成。

  • 有序性

    程序按照代码的前后顺序执行。

这个主要是由于CPU自己可能会对指令进行重排序,在某些须要严格控制顺序的代码中,须要保持其有序。

  • 可见性

    多个线程同时访问某个变量的时候,其中一个线程对变量进行了修改,这个变量的新值能够立刻同步到另外一个线程。

   

关于如何保障以上三要素,后面会讲到。

   

关于高并发与多线程相关的概念,主要就是以上这些,在以后的内容中,会继续写到线程的实现方式和主要方法,锁,多线程中的封装类等相关内容,感谢。

相关文章
相关标签/搜索