发现自己有很多读书笔记了,但是一直都是自己闷头背,没有输出,突然想起还有博客圆这么个好平台给我留着位置,可不能荒废了。

此文读的书是《Jvava并发编程的艺术》,方腾飞等著,非常经典的一本书,本笔记是一边复习笔记,一边对照书本上的勾画重点,互相补充得来。


一、并发编程的目的与挑战

并发编程的目的只有一个:更充分的利用好计算资源,让程序运行的更快更有效率

请把这个目的牢记在心,因为,并不是启动更多的线程就能让程序最大限度的并发执行的,因为配合,甚至管理更多的线程本身也是有开销的。所以至少来说,利用并发编程来提升程序效率还面临着以下几项挑战:

  • 上下文切换
  • 死锁
  • 硬件与软件资源限制

1、上下文切换

什么是上下文切换?考虑一个CPU流水线式处理多个进程的情况,我们知道。CPU通过轮流分配给各个进程以一定的时间片来实现并发执行,那么当CPU在作出时间片的切换时,必须要保存上一个任务的状态,以便后续接着上次的位置进行处理,随后再将下一个任务之前运行到的状态(如果有的话)读取加载进入CPU,这就是上下文切换,很明显,这样的切换是会影响效率的。

为什么这样的切换影响效率?

因为CPU是整个计算机结构中处理速度最快的结构,在整个计算机组成结构中,距离CPU越近的存储器就越是寸土寸金,自然不能大量留给那些已经被换下CPU的进程。

通常来说,换下CPU的进程的上下文会作为匿名页保存在内存当中,而内存与距离CPU最近的高速缓存有100倍的访问速度差距,更不用提寄存器了,所以频繁的进行上下文切换必然是会带来性能损失的

考虑到CPU的时间片往往持续非常短,一秒钟就可能需要上千次上下文切换,如何避免它就成为了我们提高并发效率的核心。

减少上下文切换,比较常用的办法有:

  • 无锁并发编程
  • CAS算法
  • 使用最少线程编程
  • 使用协程

下面具体来看。

无锁并发编程

​ 由于多线程竞争锁时,会引起上下文切换,所以多线程处理数据时可以尽量避免锁。比如可以根据数据ID取模来将数据分段,然后不同线程处理不同段的数据

CAS算法

​ Java的Atomic包就是使用CAS算法来更新数据的,这种办法不需要加锁。

​ CAS (Compare And Swap 比较交换算法),其实现方式是基于硬件平台的汇编指令,在intel的CPU中,使用的是cmpxchg指令,也就是说CAS是靠硬件实现的,从而在硬件层面提升效率。这里还需要引入两个概念:

  • 乐观锁,总是认为当前是线程安全的,不怕别的线程修改变量,所以并不真正上锁。只是在每次读写时判断一下临界区是否已经被其他线程修改,如果修改了,就(通常是通过循环)再重新读取被修改后的数据再处理。CAS算法就属于这类
  • 悲观锁:总是认为当前是线程不安全的,不管什么情况都进行加锁,任何线程再读写时若获取锁失败,则阻塞。许多经典的锁机制如synchronized关键字都属于这类方法。

既然CAS算法是乐观锁的一种,那么也就是说,CAS并不会真的在并发时给临界区加锁,那么如何保证不会出现错误呢?下面来看CAS算法的原理,如图所示,当线程开启时,会从主存中给每个线程拷贝一个变量副本到线程各自的运行环境中,CAS算法中包含三个参数(V,E,N),V表示主存中该变量的值、E表示之前拷贝到的预期值、N表示此次更新后的新值。

那么现在有两个线程t1,t2。他们各自的运行环境中都有共享变量的副本V1、V2,预期值E1、E2,预期主存中的值还没有被改变,假设现在在并发环境,t1先拿到了执行权限,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次发起尝试(只要还处于时间片中),然后t1比较预期值E1和主存中的V,发现E1=V,说明预期值是正确的,执行N1=V1+1,并将N1的值传入主存。这时候贮存中的V=21,然后t2又紧接着拿到了执行权,比较E2和主存V的值,由于V已经被t1改为21,所以E2!=V,t2线程将主存中已经改变的值更新到自己的副本中,再发起重试;直到预期值等于主存中的值,说明没有别的线程对旧值进行修改,则继续执行代码。

CAS算法很重要,它是Java并发编程里很多技术的基石。

使用最少线程

简单直白,我们避免创建不必要的线程,从而避免出现大量线程等待的情况。

协程

在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。


2、死锁

显然在多线程编程中,锁是一种非常有用的工具,其运用场景极多,因为它使用简单且易于理解。不过,一旦滥用锁就会大大折损效率,更可怕的是有可能会造成死锁。

死锁要发生需要满足四个条件,缺一不可:

  • 互斥条件

    • 即目标资源是不可共享的,多个进程不能同时持有该资源
  • 持有并等待条件
    • 一旦某个进程持有该资源,则在该进程运行结束前,不会主动释放资源
  • 不可夺占条件
    • 其他进程不能抢夺已经被某个进程所持有的资源
  • 循环等待条件
    • 进程之间获取这些互斥资源的顺序形成了环形链

死锁本身很简单,就是因为某些原因导致两把锁或者更多锁的持有进程在相互等待,永无止境。解决死锁不难,只要破坏死锁四大条件中的任意一条即可。

一般而言我们有以下方法:

  • 避免一个线程同时获取多个锁
  • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
  • 尝试使用定时锁,即lock.tryLock(timeout)替代内部锁机制
  • 对于数据库锁,加锁与解锁必须在一个数据库链接里,否则可能出现解锁失败的情况
  • 保证需要请求互斥资源的进程都以完全相同的顺序去请求资源

3、资源限制

资源限制表示由于硬件或软件的硬性指标不能支持过高并发而引起的性能限制。最简单的例子就是,如果网络就2Mb/s,而某个资源的下载速度是1Mb/s,你即便启动10个线程来进行下载,也不可能达到10Mb/s。而对于并发程序来说,网络带宽,硬盘读写速度,CPU,GPU处理速度,软件资源限制以及socket连接数等等都可能成为这个障碍。

而要解决这个问题,我们能做的只有开源与节流

  • 开源:尝试获取更多的资源,一台计算机无法处理,可以通过Hadoop等平台搭建一个计算机集群,通过大量计算机一同处理。其他资源同理
  • 节流:根据我们所持有的资源量,设定一个合理的并发度,控制线程数量在一个合适的范围中

《Java并发编程的艺术》读书笔记:一、并发编程的目的与挑战的更多相关文章

  1. Java并发编程的艺术读书笔记(2)-并发编程模型

    title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...

  2. Java并发编程的艺术读书笔记(1)-并发编程的挑战

    title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...

  3. synchronized的实现原理-java并发编程的艺术读书笔记

    1.synchronized实现同步的基础 Java中的每个对象都是可以作为锁,具体有3种表现. 1.对于普通同步方法,锁是当前实例对象. 2.对于静态同步方法,锁是当前类的Class对象. 3.对于 ...

  4. 《Java并发编程实战》读书笔记一 -- 简介

    <Java并发编程实战>读书笔记一 -- 简介 并发的历史 并发的历史,也是人类利用有限的资源去提高生产效率的一个的例子. 设想现在有台计算机,这台计算机具有以下的资源: 单核CPU一个 ...

  5. 《Java编程思想》读书笔记(二)

    三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...

  6. 《Java编程思想》读书笔记(四)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...

  7. 《Java编程思想》读书笔记(五)

    前言:本文是<Java编程思想>读书笔记系列的最后一章,本章的内容很多,需要细读慢慢去理解,文中的示例最好在自己电脑上多运行几次,相关示例完整代码放在码云上了,码云地址:https://g ...

  8. 《Go并发编程实战》读书笔记-语法概览

    <Go并发编程实战>读书笔记-语法概览 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客我们会快速浏览一下Go的语法,内容涉及基本构成要素(比如标识符,关键字,子 ...

  9. 《Go并发编程实战》读书笔记-初识Go语言

    <Go并发编程实战>读书笔记-初识Go语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在讲解怎样用Go语言之前,我们先介绍Go语言的特性,基础概念和标准命令. 一. ...

  10. 《Linux/Unix系统编程手册》读书笔记 目录

    <Linux/Unix系统编程手册>读书笔记1  (创建于4月3日,最后更新4月7日) <Linux/Unix系统编程手册>读书笔记2  (创建于4月9日,最后更新4月10日) ...

随机推荐

  1. 故障案例 | lsof是怎么"影响"MySQL计算打开文件句柄数的

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 lsof中附加不同参数产生的结果也不同,小心"踩坑". 1. ...

  2. Vnc自动登录器-多国语言绿色版

    推荐:介绍一个VNC连接工具:iis7服务器管理工具.IIs7服务器管理工具可以批量连接并管理VNC服务器.作为服务器集成管理器,它最优秀的功能就是批量管理windows与linux系统服务器.vps ...

  3. 在.NET 6.0中使用不同的托管模型

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第六篇.在本章中,我 ...

  4. 如何免费申请js.org二级域名

    最近看到很多人都去申请了js.org的域名,我就来写个教程吧! (本教程只注重于申请域名,而不是如何使用Github) 看看成品:https://butterfly.js.org/ 官网是这么写的: ...

  5. 聊天机器人框架Rasa资源整理

      Rasa是一个主流的构建对话机器人的开源框架,它的优点是几乎覆盖了对话系统的所有功能,并且每个模块都有很好的可扩展性.参考文献收集了一些Rasa相关的开源项目和优质文章. 一.Rasa介绍 1.R ...

  6. CF1204E Natasha, Sasha and the Prefix Sums (卡塔兰数推理)

    题面 题解 把题意变换一下,从(0,0)走到(n,m),每次只能网右或往上走,所以假设最大前缀和为f(n),那么走的时候就要到达但不超过 y = x-f(n) 这条线, 我们可以枚举答案,然后乘上方案 ...

  7. PHP实现获取本地视频进行随机播放

    创建一个文件夹,里面随便方视频文件即可 列如文件夹名字是assets代码如下 <? $handler = opendir('./assets/mp4/');//当前目录中的文件夹下的文件夹 需要 ...

  8. 部署k8s的heapster监控

    Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS heapster监控目前官网已经不更新,部署学习使用 heapster: 收集监控数据 influxdb:数 ...

  9. Python实现XMind测试用例快速转Excel用例

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/c2d10f21.html 你好,我是测试蔡坨坨. 今天分享一个Python编写的小工具,实现XMind测试用例转Excel用 ...

  10. KingbaseES V8R6 集群环境wal日志清理

    案例说明: 1.对于集群中的wal日志,除了需要在备库执行recovery外,在集群主备切换(switchover或failover)时,sys_rewind都要读取wal日志,将数据库恢复到一致性状 ...