《Jave并发编程的艺术》学习笔记(1-2章)
Jave并发的艺术
并发编程的挑战
上下文切换
CPU通过时间片分配算法来循环执行任务,当前时间片执行完之后会切换到下一个任务。但是,切换会保存上一个任务的状态,一遍下次切换回这个任务时,可以再次加载这个状态。所以任务从保存到再加载的过程就是一次上下文切换。
如何减少上下文切换
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程
- 无锁并发编程:多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法避免使用锁,如将数据ID按照Hash算法取模分段,不同的线程处理不同段的数据
- CAS算法:Java的Atomic包使用CAS算法来更新数据,而不需要加锁
- 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态
- 协程:在单线程实现多任务的调度,并在单线程里维持多个任务间的切换
死锁
死锁常见的原因是,线程之间相互等待。避免死锁的几个常见方法:
- 避免一个线程获取多个锁
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
- 尝试使用定时锁,使用lock.tryLock(timeout)来代替使用内部锁机制
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
底层实现原理
volatile
volatile的定义与实现原理
Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获取这个变量。所以java提供了volatile,在某些情况下面比锁更加的方便。如果一个字段被声明为volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。
volatile如何保证可见性:通过Lock前缀指令,对volatile进行写时,JVM会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存
- Lock前缀指令会引起处理器缓存行写回到内存
- 一个处理器的缓存回写会导致其他处理器的缓存无效
synchronized
synchronized的介绍
并发编程里面元老级别的存在,重量级的锁。Java里面每一个对象都可以作为锁
- 对于普通的方法,锁是当前实例的对象
- 对于静态同步方法,锁是当前类的Class对象
- 对于同步方法块,锁是Synchronized括号里配置的对象
Java对象头
synchronized用的锁是存在Java对象头里面的。对象头的内容
- Mark Word:存储对象的HashCode或锁信息
- Class Metadata Address:储存到对象类型数据的指针
- Array length:数组的长度
Mark Word里默认存储对象的HashCode、分代年龄和锁标记,Mark Word里储存的数据会随着锁标志位的变化而变化。以下是四种状态的变化
- 轻量级锁:指向栈中锁记录的指针,锁标志位 00
- 重量级锁:指向互斥量(重量级锁)的指针 ,锁标志位 10
- GC标记:空,锁标志位 11
- 偏向锁:线程ID,Epoch,对象分代年龄,是否是偏向锁,锁标志位 01
锁的升级与对比
锁一共有四种状态,级别从低到高依次是:无锁状态、偏向锁状态,轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。注意:锁可以升级但是不能够降级。一些的设计目的只有一个。为了提高获得锁和释放锁的效率
- 偏向锁:大多数情况下,锁不仅不存在多线程竞争,而且总是由他同一个线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。如:当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程再次进入和退出同步块时不需要进行CAS操作来加锁和解锁,仅仅判断一下对象头里面的Mark Word里面是否存储着指向当前线程的偏向锁。如果有,表示当前线程已经获得了锁;如果没有,则使用CAS竞争锁,再尝试使用CAS将对象头的偏向锁指向当前线程
- 轻量级锁:线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用于储存记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程就会获得锁,如果失败,表示其他线程竞争锁,当前线程便可以尝试通过自旋来获取锁,自旋失败之后,锁就会膨胀成重量级锁
- 重量级锁:因为自旋会消耗CPU,为了避免无用的自旋(如:获得锁的线程被阻塞住了),一旦锁升级为重量级锁就不会恢复到轻量级锁状态。当锁出于这个状态下,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进入新一轮的夺锁之争
原子操作的实现原理
原子(atomic),不能被进一步分割的最小粒子,原子操作:不能被中断的一个或一系列的操作。
处理器如何实现原子操作
- 第一个机制,通过总线锁来保证原子性
- 第二个机制,通过缓存锁定来保证原子性
Java如何实现原子操作
可以通过锁,和循环CAS的方式实现原子操作
CAS
CAS(Compare And Swap):比较并且交换。一个旧值,一个新值,操作之前比较旧值有没有发生变化,如果没有发生变化,才换成新值,发生了变化则不交换
CAS存在的三大问题:
- ABA问题:CAS操作需要在操作的值的时候,检查值有没有发生变化。但是如果一个值原来是A,变成了B,又变成了A,使用CAS进行检查时会发现他的值没有发生变化,但是实际上他发生了变化。解决方案:给变量加上版本号
- 循环时间长开销大:自旋CAS如果不成功,会给CPU带来非常大的开销
- 只能保证一个共享变量的原子操作:JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作
《Jave并发编程的艺术》学习笔记(1-2章)的更多相关文章
- 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: 读书笔记 --- ...
- 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象
Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...
- Java并发编程的艺术(一、二章) ——学习笔记
第一章 并发编程的挑战 需要了解的一些概念 转自 https://blog.csdn.net/TzBugs/article/details/80921351 (1) 同步VS异步 同步和异步通常用来 ...
- 《Java并发编程的艺术》笔记
第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种:无锁并发编程.CAS算法.使用最少线程.使 ...
- 《Java并发编程实战》学习笔记
第2章 线程安全性 正确性: 某个类的行为与其规范完全一致. 2.1线程安全: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或 ...
- 《Java并发编程实战》学习笔记 任务执行和取消关闭
查看豆瓣读书 第六章 任务执行 大多数并发应用程序是围绕执行任务进行管理的.设计任务时,要为任务设计一个清晰的任务边界,并配合一个明确的任务执行策略.任务最好是独立的,因为这会提高并发度.大多数服务器 ...
- <<Java并发编程的艺术>>-阅读笔记和思维导图
最近在坚持每天阅读<>,不但做好笔记(MarkDown格式),还做好思维导图. 如果大家感兴趣,可以可以到码云上阅读笔记和到ProcessOn上阅读思维导图. 码云:https://git ...
- synchronized的实现原理-java并发编程的艺术读书笔记
1.synchronized实现同步的基础 Java中的每个对象都是可以作为锁,具体有3种表现. 1.对于普通同步方法,锁是当前实例对象. 2.对于静态同步方法,锁是当前类的Class对象. 3.对于 ...
随机推荐
- 腾讯云Unubtu 16.04 (gunicorn+supervisor+ngnix+mongodb)部署Flask应用
1.申请腾讯云服务 我申请了免费使用的云服务器 ,选择安装的Linux版本是ubuntu16.04.1 LTSx86_64.我个人PC安装使用的也是这个版本,比较熟悉些. 详细参考帮助文档. 2.登录 ...
- [ Java面试题 ]基础篇之二
1.String s = new String("xyz");创建了几个StringObject?是否可以继承String类? 两个或一个都有可能,"xyz"对 ...
- 【转】详解JavaScript中的异常处理方法
有三种类型的编程错误:(1)语法错误和(2)运行时错误(3)逻辑错误:语法错误: 语法错误,也被称为解析错误,在编译时进行传统的编程语言,并出现在JavaScript解释时. 例如,下面一行将导致一个 ...
- 10个Python练手小程序,学习python的很好的资料
[程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列 ...
- Activity的运行过程
今天看到了这个关于Activity的过程这个方面的知识,之前我其实也是做过安卓项目的,也是有安卓开发的一定经验的,但是我发现之前似乎是知其然,而不知其所以然,之前来说只知道activity里的onCr ...
- 导入https证书
摘 要 JSSE是一个SSL和TLS的纯Java实现,通过JSSE可以很容易地编程实现对HTTPS站点的访问.但是,如果该站点的证书未经权威机构的验证,JSSE将拒绝信任该证书从而不能访问HTTPS站 ...
- java获取一个月的天数
import java.text.SimpleDateFormat; import java.util.Calendar; public class Test { public static void ...
- 你不知道的JavaScript--Item20 作用域与作用域链(scope chain)
作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...
- W3C------JS
✄--------------------------------------------分割线--------------------------------------------✄ W3C:ht ...
- 终于将 SQL Server 成功迁移至 MySQL8.0 啦!!!
之前一直使用 SQL Server 作为主数据库而不是 MySQL ,原因之一是单机 SQL Server 性能比 MySQL 强很多,另一个原因是之前客户的系统管理员大多只有 SQL Server ...