Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

加餐 | 什么是数据的强、弱一致性?

刘超 2019-07-06
你好,我是刘超。
第 17 讲讲解并发容器的时候,我提到了“强一致性”和“弱一致性”。很多同学留言表示对这个概念没有了解或者比较模糊,今天这讲加餐就来详解一下。
说到一致性,其实在系统的很多地方都存在数据一致性的相关问题。除了在并发编程中保证共享变量数据的一致性之外,还有数据库的 ACID 中的 C(Consistency 一致性)、分布式系统的 CAP 理论中的 C(Consistency 一致性)。下面我们主要讨论的就是“并发编程中共享变量的一致性”。
在并发编程中,Java 是通过共享内存来实现共享变量操作的,所以在多线程编程中就会涉及到数据一致性的问题。
我先通过一个经典的案例来说明下多线程操作共享变量可能出现的问题,假设我们有两个线程(线程 1 和线程 2)分别执行下面的方法,x 是共享变量:
//代码1
public class Example {
int x = 0;
public void count() {
x++; //1
System.out.println(x)//2
}
}
如果两个线程同时运行,两个线程的变量的值可能会出现以下三种结果:

Java 存储模型

2,1 和 1,2 的结果我们很好理解,那为什么会出现以上 1,1 的结果呢?
我们知道,Java 采用共享内存模型来实现多线程之间的信息交换和数据同步。在解释为什么会出现这样的结果之前,我们先通过下图来简单了解下 Java 的内存模型(第 21 讲还会详解),程序在运行时,局部变量将会存放在虚拟机栈中,而共享变量将会被保存在堆内存中。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(20)

  • THROW
    老师您好,都说concurrenthashmap的get是弱一致性,但我不理解啊,volatile 修饰的变量读操作为什么会读不到最新的数据?

    作者回复: 我们知道Node<k,v>以及Node<k,v>的value是volatile修饰的,所以在一个线程对其进行修改后,另一个线程可以马上看到。
    如果是一个新Node,那么就不能马上看到,虽然Node的数组table被volatile修饰,但是这样只是代表table的引用地址如果被修改,其他线程可以立马看到,并不代表table里的数据被修改立马可以看到。

    2019-07-08
    1
    9
  • Liam
    老师好,请教一个问题:

    文中举例,数据不一致是多核CPU的高速缓存不一致导致的,是否意味着单核CPU多线程操作就不会发生数据不一致呢

    作者回复: 也会的,线程安全除了要保证可见性,还需要保证原子性、有序性。

    2019-07-06
    4
  • 明翼
    早看到就好了😁,老师请教下这么多知识点你是怎么记住的?

    作者回复: 平时善于做笔记,除此之外,尝试将自己学到的知识点分享给其他人。

    2019-07-10
    3
  • Lost In The Echo。
    老师,请问强一致性和顺序一致性有什么区别吗?

    作者回复: 顺序一致性是指单个线程的执行的顺序性,强一致性则指的是多个线程在全局时钟下的执行的顺序性。

    2019-07-06
    3
  • 青梅煮酒
    老师,请问一下,每核CPU都有自己的L1和L2,那么L1和L2的主要区别是什么呢?为什么不能合到一起呢?

    作者回复: L1\L2\L3三个缓存的作用和实现的技术是不一样的,L1的内存大小是非常有限的,所以很多时候在L1获取缓存数据的命中率非常低。为了提高CPU读取的速率,在L1没有命中的缓存,可以进入到L2进行获取,L2的容量要比L1大,但离CPU核心更远。但还是能提高CPU读取缓存数据的速率。

    2019-07-16
    1
  • 东方奇骥
    上面例子,flag加volatile修饰,根据happens before中的顺序性选择和volatile的原则,就能保证另一个线程读到写入的值了。

    作者回复: 对的,volatile除了可以保证变量的可见性,可以阻止局部指令重排序。

    2019-07-06
    1
  • 赤城
    由于编译优化,可能会导致执行指令重排序的问题,为此Java内存模型中引入了happen-before规则,即便学习Java开发这么多年,再看这个原则还是有很多晦涩难懂的地方。前人栽树,后人乘凉,感谢设计Java语言的大神们搞出这么牛X的方案,让大部分开发者在并发编程也几乎不必考虑这个重排序问题。

    作者回复: 是的

    2019-11-08
  • 老师,我指出一个错误,时序图中最后flag=true不是false

    作者回复: 收到,谢谢提醒

    2019-10-25
  • 菜菜
    针对老师对留言1的回复,我想问下老师,Node<k,v>中除了value被volatile修饰了,next也被volatile修饰了呀,这样如果是新增新的Node的话,其他线程也不可以看到吗?

    作者回复: 获取节点时是通过key值获取,并不一定通过next获取,所以不能代表对应key值中的value是最新的

    2019-10-08
  • 疯狂咸鱼
    老师可以不可以讲一下threadlocal

    作者回复: mark

    2019-09-21
  • godtrue
    数据只要在不同的地方,且存在写操作就可能存在不一致性。不管是各级缓存中还是分布式集群中的某些节点中,都有类似的问题。线程间的数据一致性问题,由操作系统来去保证,分布式系统中的数据一致性问题由分布式协议的实现者去保证,不过确实不好弄,令人头疼。
    给老师点赞,讲的很棒,不过知识真是太多了,感觉越学越多,买的专栏都学不完,不学是不行的不进则退,如果英语好就占优势了,可以直接学习第一手的学习资料。

    作者回复: 坚持看英文文档,到最后你就能流利的读任何英文文档说明了

    2019-09-10
  • Demon.Lee
    专栏值啊,奋起直追,追呀
    2019-08-31
  • K
    老师好,网上的文章一直在说,volatile关键字,有可见性,有序性,不保证原子性。对于可见性是比较清楚的。对于有序性,结合老师刚刚那个图,我理解是单个线程执行的时候,代码肯定是有序执行的。多个线程执行,还是会出现乱序的情况。就像老师图里画的那样,是一个顺序一致性,不是强一致性。另外:希望老师能讲讲volatile的内存屏障,那块来来回回看总是不理解。谢谢老师。
    2019-07-24
  • 面朝大海
    int x = 1;// 步骤 1:加载 x 变量的内存地址到寄存器中,加载 1 到寄存器中,CPU 通过 mov 指令把 1 写入到寄存器指定的内存中
    boolean flag = true; // 步骤 2 加载 flag 变量的内存地址到寄存器中,加载 true 到寄存器中,CPU 通过 mov 指令把 1 写入到寄存器指定的内存中
    int y = x + 1;// 步骤 3 重新加载 a 变量的内存地址到寄存器中,加载 1 到寄存器中,CPU 通过 mov 指令把 1 写入到寄存器指定的内存中
    2019-07-08
  • -W.LI-
    老师好volatile+cas是强一致性么?。L1直接刷回主存,L2和L3需要做什么操作么?开头说每一级都是上一级的子集来着。

    作者回复: cas+volatile可以解决单个变量的强一致性问题。

    2019-07-07
  • 云封
    老师,请问下,如果不存在操作共享变量的情况或者把共享产量存在redis中,多线程结果就不会发生由于指令重排而导致结果不一致的情况。

    作者回复: 指令重排序不一定是由于共享变量导致的,这块需要结合具体的场景分析。

    2019-07-07
  • Jxin
    请问老师,指令重排优化会受多线程影响吗?感觉应该不会出现赋值为true和x=1这两条指令对换位置。因为从单线程来看这没有指令重排的价值,所以感觉不会做重排优化。而如果重排优化会受多线程影响,那么场景1的r1==1应该是赋值为true,然后进入了if逻辑,接着优先执行x=1才导致的r1==1的结果。布尔赋值为true和if判断应该要紧挨着,减少一次寄存器加载该临时变量值。也就是老师那个场景1不会出现。

    作者回复: 这里只是假设,有专门一个指令重排序的例子。

    2019-07-06
  • -W.LI-
    老师容我问一个很基础的问题!父类private的属性会被子类继承么?子类创建的时候JVM给子类分配内存的时候,我看书上有说父类的属性会排在子类前面有可能穿插。可是没写是否会给子类分配父类的私有属性内存空间。子类创建的时候,会默认调用父类的无参构造器。这时候就会实例化一个父类对象么?(如果父类没有无参构造器会报错或者需要显示调用父类的有参构造器)。如果每次实力子类对象的时候都会先创建一个父类对象的话,滥用继承。就会浪费很多内存是么?对象头就需要8字节了。

    作者回复: 子类会继承父类的private属性,但子类无法直接访问到private属性;
    子类创建时,不会创建一个父类对象的,只是调用了父类的构造函数初始化而已。

    2019-07-06
  • 密码123456
    单核也会有问题的,还有重排序。

    作者回复: 会有重排序问题

    2019-07-06
  • nightmare
    点赞666
    2019-07-06
收起评论
20
返回
顶部