多线程开发之前你必须了解的基本概念

在进行多线程开发之前,你应该了解以下基本常识,帮助你正确的处理线程,以及灵活安全的使用线程

有些理论比较晦涩,需要单独章节才能介绍完,本套教程将在晦涩的概念后面附上单独的章节完整介绍

同步(Synchronous)和异步(Asynchronous)

同步和异步强调的是程序执行的方向流程性,同步属于顺序性,而异步则不必是

概念

同步

指在进行一系列操作的时候,如果任务没有执行完成,将会一直进行等待,直到系统返回结束调用。

常见例子,如,A向B打电话,如果B一直没有接听,将不能完成通话,直到B接听,我们才可以通话,在接通时,我们必须时刻注意B接听,而不能干其他事情。

异步:

指在进行一系列操作的时候,调用者无需等待被调用者,将会继续处理其他的事情

常见例子,如,A向B发送短信,A只要编辑好短信内容发送出去就可以去干别的事情了,而不需要实时等待B接收和回复

使用场景

同步:

  • 用户登陆,用户在请求登陆的时候必须同步等待系统返回结果,告知密码错误或者登陆成功,期间不能干其他事情
  • AB两个请求有顺序依赖要求,必须A调用完成后方可调用B

异步:

  • 无刷新获取数据,网页中通过Ajax异步请求数据,实现无刷新获取数据,异步获取数据然后回调处理方法
  • 异步通知,用户注册成功,并不需要等待通知方法执行完成,而用异步通知,减少等待时间,提高系统利用率

优点好处

同步:

  • 同步流程对结果处理通常更为简单,可以就近处理
  • 同步流程对结果的处理始终和前文保持在一个上下文内
  • 同步流程可以很容易捕获、处理异常
  • 同步流程是线性处理方式,便于我们编写代码

异步:

  • 异步流程可以立即给调用方返回初步的结果,而实际结果后续通知
  • 异步流程可以延迟给调用方最终的结果数据,在此期间可以做其他事情
  • 异步流程在执行的过程中,可以释放占用的线程等资源,避免阻塞
  • 异步流程可以等多次调用的结果出来后,再统一返回一次结果集合,提高响应效率

阻塞(Blocking)和非阻塞(Non-Blocking)

阻塞和非阻塞强调的是对于结果的等待方式,阻塞是一直等待被调用方返回结果,而非阻塞则不是一直等待

概念

阻塞:

如果一个程序单元的某个操作,在等待这个操作完成的过程中程序单元它自身无法继续进行下去做别的事情,那就称这个程序单元在等待该操作时是阻塞的。常见的阻塞形式有网络I/O阻塞,磁盘I/O阻塞,用户输入阻塞,CPU阻塞等等

非阻塞:

非阻塞就是阻塞的反面。即是如果一个程序单元的某个操作,在等待这个操作完成的过程中程序单元它自身可以继续进行下去做别的事情,那就称这个程序单元在等待该操作时是非阻塞的。

同步 异步 和 阻塞 非阻塞的联系区别

阻塞同步:基本上就是最直观但最没效率的方式,一个请求进来,请求方会一直等它的档案,而被请求方在档案准备好之前不会做任何回覆,两个人都会卡在那直到事情完成。
举例:一堆人到星巴克柜台买咖啡,每一个买咖啡的人都会一直站在柜台前一直等,直到柜台给他咖啡。

非阻塞同步:请求方变聪明了,请求如果当下没得到回覆,它会跑去做其他的事情,但是因为被请求方还是不会主动通知,所以每隔一段时间就要重新送一次请求。
举例:买咖啡的人变聪明了,他会去旁边滑滑手机做其他事,但是柜台人员不会主动跟客人说咖啡好了,变成客人每五分钟要去问咖啡好了没,对客人来说还是很没效率。

阻塞异步:被请求方变聪明了,不管档案是否可以被读取,都会回传讯息给请求方,但是请求方怎么样都会等待,所以会不会通知根本没差。
举例:柜台变聪明了,他会主动通知客人咖啡好了,但是客人不管怎么样都还是会占着柜台等他的咖啡,所以有通知跟没通知一样。

非阻塞异步:这就是目前比较有效率的处理方式,假设档案一样无法被读取,请求方送出请求时,被请求方会立刻回传档案被使用的讯息,而请求方也会乖乖离开去做其他事,被请求方则会在档案可以读取时主动通知请求方。
举例:两个人都变聪明了,客人到柜台前去买咖啡,得到柜台人员给的号码牌后就离开柜台,柜台人员则继续帮下一个人点餐,当客人的咖啡准备好时,柜台人员就会主动呼叫号码,叫客人前来领取咖啡。

并发(Concurrency)和并行(Parallelism)

概念

并发:

一个处理器同时处理多个任务,通常是指通过CPU时间片段来回切换上下文针对多线程处理任务

例如:如果只有一个咖啡机,大家可以排成两队,依次交替使用咖啡机

并行:

多核的处理器同时处理多个不同的任务,通常是指多个CPU对应处理多个任务,不存在上下文切换

例如:如果有两台咖啡机,那么大家可以排成两队使用咖啡机,两队之间不存在交替行为

竞态条件,临界区,互斥量,信号量,事件的区别

竞态条件:

多线程对同一共享资源进行修改的时候,如果对资源的访问顺序敏感,就称存在竞态条件

临界区:

导致竞态条件发生的代码区称作临界区

互斥量:

协调共同对一个共享资源的单独访问而设计的

是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性

信号量:

为控制一个具有有限数量资源而设计

信号量允许多个线程同时使用共享资源

详细参考 信号量

事件:

用来通知线程有一些事件已发生,从而启动后续任务的开始

事件对象也可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作

JMM(内存模型)

Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM),用于屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果,JMM规范了Java虚拟机与计算机内存是如何协同工作的:规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值,以及在必须时如何同步的访问共享变量。

由于Java内存模型涉及内容复杂,在这里并不能详细解说,请加QQ群:368512253 获取专业资料查看

CAS(Compare and Swap)算法

中文翻译:比较并交换

CAS,即 Compare And Swap(比较与交换),是一种无锁算法,基于硬件CPU实现,能够在不使用锁的情况下实现多线程之间的变量同步。JDK中的java.util.concurrent.atomic包中的原子类就是通过CAS来实现了乐观锁。

CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

AQS(AbstractQueuedSynchronizer)抽象队列同步器

AQS(AbstractQueuedSynchronizer),AQS是JDK下提供的一套用于实现基于FIFO等待队列的阻塞锁和相关的同步器的一个同步框架。常用的ReentrantLock/Semaphore/CountDownLatch等等都是实现了AQS

AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。

CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。

更多内容可查询相关资料,推荐一个文章 AbstractQueuedSynchronizer源码图文分析

Happens-Before法则

在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

详细参考

指令重排序

重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。

有锁并发

主要是利用锁的机制,阻塞线程,避免线程竞争访问同一资源

常见:synchronized关键字 Lock锁

无锁并发

主要是利用CAS算法实现无锁并发

常见:AtomicInteger

温馨提示:以上每个概念,限于篇幅,很难具体说清楚,更多的大家要去查资料弄懂,这里提供这些基础概念,将会为我们在后续真正的实际操作上提供理论支持

本套教程是一套全面覆盖JAVA多线程的教程,其他章节可登陆网站查看
涵盖内容:包括但是不限制,线程基础理论,线程安全,锁,调度机制,线程通信,并发容器,并发框架,并发工具类,线程池,线程性能测试与问题定位

 Java线程生命周期和运行流程中的状态切换
总是说多线程到底多线程是什么 
上一篇:Java线程生命周期和运行流程中的状态切换
下一篇:总是说多线程到底多线程是什么
评论

如果我的文章对你有帮助,或许可以打赏一下呀!

支付宝
微信
QQ