《Java并发编程的艺术》读书笔记:一、并发编程的目的与挑战
发现自己有很多读书笔记了,但是一直都是自己闷头背,没有输出,突然想起还有博客圆这么个好平台给我留着位置,可不能荒废了。
此文读的书是《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并发编程的艺术》读书笔记:一、并发编程的目的与挑战的更多相关文章
- Java并发编程的艺术读书笔记(2)-并发编程模型
title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...
- Java并发编程的艺术读书笔记(1)-并发编程的挑战
title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...
- synchronized的实现原理-java并发编程的艺术读书笔记
1.synchronized实现同步的基础 Java中的每个对象都是可以作为锁,具体有3种表现. 1.对于普通同步方法,锁是当前实例对象. 2.对于静态同步方法,锁是当前类的Class对象. 3.对于 ...
- 《Java并发编程实战》读书笔记一 -- 简介
<Java并发编程实战>读书笔记一 -- 简介 并发的历史 并发的历史,也是人类利用有限的资源去提高生产效率的一个的例子. 设想现在有台计算机,这台计算机具有以下的资源: 单核CPU一个 ...
- 《Java编程思想》读书笔记(二)
三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...
- 《Java编程思想》读书笔记(四)
前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...
- 《Java编程思想》读书笔记(五)
前言:本文是<Java编程思想>读书笔记系列的最后一章,本章的内容很多,需要细读慢慢去理解,文中的示例最好在自己电脑上多运行几次,相关示例完整代码放在码云上了,码云地址:https://g ...
- 《Go并发编程实战》读书笔记-语法概览
<Go并发编程实战>读书笔记-语法概览 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客我们会快速浏览一下Go的语法,内容涉及基本构成要素(比如标识符,关键字,子 ...
- 《Go并发编程实战》读书笔记-初识Go语言
<Go并发编程实战>读书笔记-初识Go语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在讲解怎样用Go语言之前,我们先介绍Go语言的特性,基础概念和标准命令. 一. ...
- 《Linux/Unix系统编程手册》读书笔记 目录
<Linux/Unix系统编程手册>读书笔记1 (创建于4月3日,最后更新4月7日) <Linux/Unix系统编程手册>读书笔记2 (创建于4月9日,最后更新4月10日) ...
随机推荐
- 游戏开发常遇到数据一致性BUG,怎么解?
摘要:数据副本强一致.全节点可写.存储全面降本,GaussDB(for Redis)重新定义游戏数据库,彻底修复一致性BUG. 本文分享自华为云社区<华为云GaussDB(for Redis)揭 ...
- MySQL的三值逻辑
MySQL 采用三值逻辑 SELECT 1 = 1; SELECT 1 = 2; SELECT 1 = NULL; SELECT 1 != NULL; 上面四条语句的结果分别为: 可见MySQL采用三 ...
- pytest-fixture执行顺序
作用域-scope 作用域越大,越先执行,session>package>module>class>function. 是否自动调用fixture 自动调用(autouse=T ...
- linux centos 系统盘文件系统损坏-已解决
当我们使用的Linux虚拟机(云服务器/vps)磁盘出现xfs文件系统损坏时,该如何进行修复? xfs格式文件系统损坏,是运维常见的一个场景,经常发生在强制重启.异常关机.软件冲突.误删文件等事件后, ...
- MySQL查询性能优化七种武器之索引下推
前面已经讲了MySQL的其他查询性能优化方式,没看过可以去了解一下: MySQL查询性能优化七种武器之索引潜水 MySQL查询性能优化七种武器之链路追踪 今天要讲的是MySQL的另一种查询性能优化方式 ...
- 试用 ModVB(一):安装教程+使用 JSON 常量和 JSON 模式匹配
前排提醒:阅读此文章并充分尝试 ModVB 的新语法需要较长的时间.对于程序员而言,如果你工作时不用 VB,则最好避免在上班时间看,以免被领导认为你在长时间摸鱼. 什么是 ModVB ModVB 是一 ...
- 二 代理模式【Proxy Pattern】 来自CBF4LIFE 的设计模式
什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被代理的人能干活呀. ...
- GNSS模块使用笔记
目录 目录 GNSS芯片 NMEA0183 协议 指令 GNSS TO MCU MCU TO GNSS GNSS芯片 ATGM336H-5N31(GPS+BDS双模) 原理图 NMEA0183 协议 ...
- 使用verdaccio+docker搭建npm私有仓库以及使用
公司内部前端组件或库的共享等,搭建一个npm私有库就很方便,现在中大型公司也基本都有自己的npm私有库,这篇文章,和大家一起共同搭建一个npm私有库,共同学习 前置条件 一台电脑 可以联网 一.安装d ...
- 《Java基础——循环语句》
Java基础--循环语句 1. while语句: 规则: 1. 首先计算表达式的值. 2. 若表达式为真,则执行循环语法,直至表达式为假,循环结束. 格式: while(表达式) 语句 ...