继续讲CAS算法,上篇文章我们知道,CAS算法底层实现,是通过CPU的原子指令来实现. 那么这里又有一个情景: 话说,有一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功.尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的.为什么这样说?我们来想象这样的场景: 在你非常渴的情况下你发现一个盛满水的杯子,你一饮而尽.之后再给…
上篇文章,我们主要讲了解决多线程之间共享数据的核心问题和解决方案,也讲了锁的简单分类. 那么,这把锁,我们应该怎么去实现呢?如果你是java语言设计者,你又会怎么去设计这个线程锁呢? 直觉告诉我们,我们可以设计一个对象或属性,用来代表锁.比如,你把共享数据区当成抽屉,那这个抽屉就可设计出有锁,有钥匙,其实锁和钥匙,就是这个抽屉的必要属性.否则,这个抽屉,也就失去主要用途了. 是的,java设计者,也是这样的想的. 在JVM的规范中,有这么一些话:     “在JVM中,每个对象和类在逻辑上都是和…
java高并发核心要点|系列1|开篇 java高并发核心要点|系列2|锁的底层实现原理 java高并发核心要点|系列3|锁的底层实现原理|ABA问题 java高并发核心要点|系列4|CPU内存指令重排序(Memory Reordering) java高并发核心要点|系列5|CPU内存伪共享…
在java高并发编程,有几个很重要的内容: 1.CAS算法 2.CPU重排序 3.缓存行伪共享 我们先来说说高并发世界中的主要关键问题是什么? 是数据共享. 因为多线程之间要共享数据,就会遇到各种问题.如下图: 如果两个线程同时写入,那怎么保证数据的一致性?是线程1先写,还是线程2先写,这是个问题.那要如何解决这个问题? 答案是:加锁. 比如,线程1先访问共享数据区,那么它就先把这块数据区锁起来.后面如果其他线程要访问这个共享区,首先要从线程1这里获取锁,才能进一步访问这个共享区.这里很好理解,…
今天,我们来学习另一个重要的概念. CPU内存指令重排序(Memory Reordering) 什么叫重排序? 重排序的背景 我们知道现代CPU的主频越来越高,与cache的交互次数也越来越多.当CPU的计算速度远远超过访问cache时,会产生cache wait,过多的cache wait就会造成性能瓶颈. 针对这种情况,多数架构(包括X86)采用了一种将cache分片的解决方案,即将一块cache划分成互不关联地多个 slots (逻辑存储单元,又名 Memory Bank 或 Cache…
上节提到的:伪共享,今天我们来说说. 那什么是伪共享呢? 这得从CPU的缓存结构说起.以下如图,CPU一般来说是有三级缓存,1 级,2级,3级,越上面的,越靠近CPU的,速度越快,成本也越高.也就是说速度方面:1级>2级>3级. 说到这里,我们要理解一个很重要的概念:缓存行.什么是缓存行? 首先我们来看这几级缓存,其中,1,2级缓存是CPU核心私有的,也就是说每个核,之间不会共享1,2级缓存,那它们之间怎么通信或共享数据呢? 答案是:3级缓存,如下图: 那core1,和core2之间,是通过什…
任何事情是有套路的,学习是如此, Java的学习,更是如此. 本文,为大家揭示 Java学习的套路 背景 Java高并发.分布式的中间件非常多,网上也有很多组件的源码视频.原理视频,汗牛塞屋了. 作为Java开发人员,该怎么选择,怎么学习,真的全部要学习吗? 还是那句话: 学习是有套路的, Java的学习,更是如此 Java的学习的套路 很多的组件,是在用的过程中学习的,如果不做深入的使用, 压根不用学,不用深入学. 大家要掌握的,就是Java高并发核心知识,或者说基础原理,也就是咱们群里小伙伴…
什么是AQS? 全称: Abstract Queued Synchronizer: 抽象队列同步器 是 java.util.concurrent.locks包下的一个抽象类 其编写者: Doug Lea (并发大佬, 整个j.u.c包都是他写的) 是 j.u.c 包的基础组件(核心) 我们先来读一下该类的英文说明注释: /** * Provides a framework for implementing blocking locks and related synchronizers * (s…
1. 什么是线程? 线程和进程的区别 在了解线程的概念前,我们应该先知道什么是进程? 进程是操作系统的基本概念之一, 它是正在执行的程序实例. * 下面的一些进程的基本概念你可以了解下 -------------------------------------------------------------------- 操作系统逻辑上将一个进程分为以下几部分(段): # 文本 程序的指令 # 数据 程序使用的静态变量 # 堆 程序可从该区域动态分配额外内存 # 栈 随函数调用和返回而增减的一片…
AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用.也就是它可以保证你在修改对象引用时的线程安全性.在介绍AtomicReference的同时,我希望同时提出一个有关原子操作的逻辑上的不足. 之前我们说过,线程判断被修改对象是否可以正确写入的条件是对象的当前值和期望是否一致.这个逻辑从一般意义上来说是正确的.但有可能出现一个小小的例外,就是当你获得对象当前数据后,在准备修…