并发编程

目录

1.为什么要引入并发编程?

2.区分并发与并行

3.并发编程的两种模型

4.Java并发编程

4.1 Java常用的锁

4.2 基于CAS的机制实现的支持并发的操作

4.3 并发编程常用的工具类

4.4 Java并行计算框架Fork/Join

5. Golang并发编程

5.1 Golang相关的锁机制

5.2 Golang的CAS机制

5.3 Golang的并发工具

5.4 Golang实现CS调用

6.其他并发编程

7.总结

8.参考文章


1.为什么要引入并发编程?

1)受限于摩尔定律失效     摩尔定律:当价格不变时,集成电路上可容纳的元器件的数目每个 18-24 个月就会翻一倍以上,性能也会提升一倍。

2)阿姆达尔定律登台       阿姆达尔定律:处理器越多,程序执行就越快,但有上限,取决于程序中串行部分的比例,并行的比例越高,多处理器的效果越明显。

图片源自网络(https://blog.csdn.net/u011186240/article/details/98600436

2.区分并发与并行

并发程序是指可以被同时发起执行的程序. 并行程序则是被设计成可以在并行的硬件上执行的并发程序. 并发程序代表了所有可以实现真正的或者可能的并发行为的程序. 并发比较宽泛, 包含了并行程序.并行程序是并发程序的一种. 例如: 1000TPS: 并发的能力         4核8线程:并行的能力

  

图片源自网络(https://www.zhihu.com/question/33515481

3.并发编程的两种模型

1)共享内存的模型 多线程编程,数据共享存在问题。 操作系统采用时间分片的机制,每个线程是获取一定的时间分片,当时间分片使用完毕,操作线程会被挂起。多线程编程时,共享数据会被多个线程读写,如何解决? 引入锁机制。公平锁,偏向锁,可重入锁,读写锁,互斥锁,自旋锁。 代表性语言:大部分语言都支持(Java/C++/Golang) ,采用共享内存存在的问题:死锁,性能差。

2)通信顺序进程 CSP(Communicating Sequential Process) 模型由并发执行的实体(线程或者进程)所组成,实体之间通过发送消息进行通信,这里发送消息时使用的就是通道,或者叫 channel。CSP 模型的关键是关注 channel,而不关注发送消息的实体。 Do not communicate by sharing memory; instead, share memory by communicating. “不要以共享内存的方式来通信,相反,要通过通信来共享内存。” 代表语言:Golang,Erlang 问题:没有共享内存便于理解

4.Java并发编程

4.1 Java常用的锁

重入锁ReentrantLock的实现参考如下源码,分公平锁和偏向锁两种。 

    

读写锁ReadWriteLock是基于重入锁实现的,如其源码中的注释的样例,RWDictionary类,读写锁读共享,写独占。

 

 Condition类,下图为Condition的源码中基于Condition实现生产消费的协调  。                                                 

        

下图为ConcurrentHashMap部分实现,采用的是分段锁,针对Hash的某一个桶进行加锁解决并发性能问题。

4.2 基于CAS的机制实现的支持并发的操作

关于锁机制,Java里面还有基于CAS的高性能的加锁机制。这里我们看一下AtomicLong的源码,如下截图。其中自增长的原子性是采用底层Unsafe类实现,原子增加是通过类似自旋锁的机制实现,不断的重试,直到最终添加成功为止,才推出循环。

          

4.3 并发编程常用的工具类

Java关于并发编程Future模式,异步处理不阻塞。Future模式是多线程开发中非常常见的一种设计模式。它的核心思想是异步调用。当我们需要调用一个函数方法时。如果这个函数执行很慢,那么我们就要进行等待。但有时候,我们可能并不急着要结果。因此,我们可以让被调用者立即返回,让他在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据的场合再去尝试获取需要的数据。

           

该图来自互联网(https://blog.csdn.net/java_lifeng/article/details/102844190

CountDownLatch:是一个计数器闭锁,通过它可以完成类似于阻塞当前线程的功能,即:一个线程或多个线程一直等待,直到其他线程执行的操作完成。

           

Semaphore:信号量,它也被更多地用来限制流量,类似阀门的 功能。如果限定某些资源最多有N个线程可以访问,那么超过N个主不允许再有线程来访问,同时当现有线程结束后,就会释放,然后允许新的线程进来。

                       

CyclicBarrier:是一个同步辅助类,它允许一组线程相互等待,直到到达某个公共屏障点(common barrier point)。通过它可以完成多个线程之间相互等待,只有当每个线程都准备就绪后,才能各自继续往下执行后面的操作。

                     

4.4 Java并行计算框架Fork/Join

从JDK1.7开始,Java提供Fork/Join框架用于并行执行任务,它的思想就是将一个大任务分割成若干小任务,最终汇总每个小任务的结果得到这个大任务的结果。 这种思想和MapReduce很像(input --> split --> map --> reduce --> output) 主要有两步: 第一、任务切分; 第二、结果合并

                         

该图来自华为的技术架构师2017技术架构峰会分享

5. Golang并发编程

5.1 Golang相关的锁机制

Golang的锁相关的操作主要集中在sync包中,sync.Mutex 对应了Java的synchronized关键字, sync.RWMutex对应了Java的ReadWriteLock锁,Once保证全局只执行一次,源码如下图。

5.2 Golang的CAS机制

Golang中也存在CAS相关的原子操作,主要集中在sync.atomic包中,我们来看其中的一个原子操作方法。Golang的CAS实现是基于底层的不同的平台的汇编语言支持的特性实现,会根据不同的平台特性调用不同的底层汇编代码实现CAS的操作。

                                                                     

                 

5.3 Golang的并发工具

Go的CSP并发模型,是通过goroutine和channel来实现的。     goroutine 是Go语言中并发的执行单位。有点抽象,其实就是和传统概念上的“线程”类似,可以理解为“线程”。     channel是Go语言中各个并发结构体(goroutine)之前的通信机制。 通俗的讲,就是各个goroutine之间通信的“管道”,有点类似于Linux中的管道。WaitGroup 可以类比为java的 CountdownLatch类。参考Golang的源码的测试用例如下图:

                   

5.4 Golang实现CS调用

基于Golang可以快速简易实现CS调用,其源码如下图所示:

             

Server端代码                                                                                                         Client端代码

6.其他并发编程

Java: 响应式编程

javascript:Promise编程

Nodejs:异步回调, 回调地狱(单线程事件循环)

Scala: Akka框架, Actor模型

7.总结

本文以主流的Java和Golang两种语言的并发编程对比,详细介绍了两种并发编程语言的源码,特性以及并发编程的工具,以满足并发的诉求。

8.参考文章

1.https://blog.csdn.net/java_lifeng/article/details/102844190

2.https://blog.csdn.net/u011186240/article/details/98600436

3.华为陶召胜老师的分享

 

 

 

 

 

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值