CAS

自旋锁,偏向锁,轻量级锁头,重量锁头,

烈酒焚心 提交于 2020-12-05 18:41:34
理解锁的基础知识 如果想要透彻的理解java锁的来龙去脉,需要先了解以下基础知识。 基础知识之一:锁的类型 锁从宏观上分类,分为悲观锁与乐观锁。 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。 java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。 悲观锁 悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。 基础知识之二:java线程阻塞的代价 java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统介入,需要在户态与核心态之间切换,这种切换会消耗大量的系统资源,因为用户态与内核态都有各自专用的内存空间,专用的寄存器等,用户态切换至内核态需要传递给许多变量、参数给内核

synchronized实现原理及其优化-(自旋锁,偏向锁,轻量锁,重量锁)

你离开我真会死。 提交于 2020-12-05 18:41:22
1.synchronized概述:   synchronized修饰的方法或代码块相当于并发中的临界区,即在同一时刻jvm只允许一个线程进入执行。synchronized是通过锁机制实现同一时刻只允许一个线程来访问共享资源的。另外synchronized锁机制还可以保证线程并发运行的原子性,有序性,可见性。 2.synchronized的原理:   我们先通过反编译下面的代码来看看Synchronized是如何实现对代码进行同步的:   步骤:首先找到存放java文件的目录,在地址栏输入cmd进入命令行,然后执行javac test.java命令,形成class文件,接着执行javap -v test.class进行反编译。 【代码示例】:同步方法 1 class thread extends Thread{ 2 Object obj= new Object(); 3 @Override 4 public synchronized void run() { 5 System.out.println("run..." ); 6 } 7 } 8 public class test { 9 public static void main(String[] args) { 10 new thread().start(); 11 } 12 } 反编译结果:   从反编译的结果来看

只能用分布式锁,也能搞定每秒上千订单的高并发优化?

我与影子孤独终老i 提交于 2020-12-05 10:00:39
今天给大家聊一个有意思的话题: 每秒上千订单场景下,如何对分布式锁的并发能力进行优化? 背景引入 首先,我们一起来看看这个问题的背景? 前段时间有个朋友在外面面试,然后有一天找我聊说:有一个国内不错的电商公司,面试官给他出了一个场景题: 假如下单时,用分布式锁来防止库存超卖,但是是每秒上千订单的高并发场景,如何对分布式锁进行高并发优化来应对这个场景? 他说他当时没答上来,因为没做过没什么思路。其实我当时听到这个面试题心里也觉得有点意思,因为如果是我来面试候选人的话,应该会给的范围更大一些。 比如让面试的同学聊一聊电商高并发秒杀场景下的库存超卖解决方案,各种方案的优缺点以及实践,进而聊到分布式锁这个话题。 因为库存超卖问题是有很多种技术解决方案的,比如悲观锁,分布式锁,乐观锁,队列串行化,Redis原子操作,等等吧。 但是既然那个面试官兄弟限定死了用分布式锁来解决库存超卖,我估计就是想问一个点:在高并发场景下如何优化分布式锁的并发性能。 我觉得,面试官提问的角度还是可以接受的,因为在实际落地生产的时候,分布式锁这个东西保证了数据的准确性,但是他天然并发能力有点弱。 刚好我之前在自己项目的其他场景下,确实是做过高并发场景下的分布式锁优化方案,因此正好是借着这个朋友的面试题,把分布式锁的高并发优化思路,给大家来聊一聊。 库存超卖现象是怎么产生的? 先来看看如果不用分布式锁

头条后台开发面经

谁说胖子不能爱 提交于 2020-12-05 02:20:31
一面(纯技术面) 队列的实现,需要注意的地方 快速排序的实现、时间复杂度分析 B树和B+树的区别、应用 HashMap的实现,扩容机制,扩容时如何保证可操作 Redis扩容机制(渐进式单线程扩容 ) Spring AOP的原理 Spring IoC的原理,如何实现,如何解决循环依赖 两线程对变量i进行加1操作,结果如何,为什么,怎么解决 CAS概念、原子类实现原理 synchronize底层实现,如何实现Lock AQS有什么特点 可见性的底层原理 JVM内存模型,为什么要这么分 本地方法栈和虚拟机栈的区别 如何查看JVM参数是否正确 TCP三次握手,如何实现 Socket编程底层如何实现 select和epoll的区别 算法:蛇形打印二叉树 二面(项目面+技术面) 项目详聊(问了很多、很细) Innodb多列索引 MySQL默认事务隔离级别,不可重复读是什么意思,如何实现可重复读 Redis服务端有20GB内存,现在要缓存200GB数据,如何处理 算法:给出[[1, 2], [3, 5], [8, 8], [15, 16], [32, 38]],求间隔 什么是堆,画了个二叉树问是否符合最小堆的结构,然后根据图叙述堆排序的详细过程。 TCP与UDP的区别,还有哪些其他的传输层协议,用来做什么的。 进程与线程的区别 ,你是怎么理解这两个概念的(快被问烂了的问题……)

图解并发包中锁的通用实现

橙三吉。 提交于 2020-12-04 10:02:39
导读 这篇文章我们来聊聊Java并发包中锁的实现。 因为这其中涉及到了一点数据结构和线程挂起、唤醒等处理流程,我将源码中的关键逻辑绘制成图片的格式,方便大家有一个更加直观的理解。 阅读完本篇文章,你将了解到: 抽象同步器AQS的实现原理 ReentrantLock实现原理 非公平锁和公平锁实现的区别 基于这些内容,您也可以自己进一步探索可中断锁的实现原理 AQS的核心是state字段以及双端等待队列 如何优雅的中断一个线程 1、包结构介绍 以下内容是基于JDK 1.8进行分析的。 我们查看下 java.util.concurrent.locks 包下面,发现主要包含如下类: 我们来构建他们的UML图: 如上图,抛开内部类,抽象类,接口,主要实现了三把锁: ReentrantLock , StampedLock , ReentrantReadWriteLock 。最常用的就是 ReentrantLock 了,关于 ReentrantLock 的详细说明以及使用案例:ReentrantLock介绍与使用 https://www.itzhai.com/cpj/introduction-and-use-of-reentrantlock.html 或者公众号发送 ReentrantLock。

CAS(乐观锁)

大兔子大兔子 提交于 2020-12-04 01:41:09
1.什么是CAS CAS(Compare And Swap)比较并替换,是线程并发运行时用到的一种技术; 2.CAS作用 乐观锁 3.其他锁机制缺点 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁。 锁机制存在以下问题: (1)在多线程竞争下,加锁、释放锁会导致比较多的 上下文切换和调度延时,引起性能问题 。 (2)一个线程持有锁会导致其它所有需要此锁的 线程挂起 。 (3)如果一个优先级高的线程等待一个优先级低的线程释放锁会导致 优先级倒置 ,引起性能风险。 volatile是不错的机制,但是 volatile不能保证原子性。 因此对于同步最终还是要回到锁机制上来。 独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。 4.CAS实现 CAS需要三个指令,分别是内存位置(JAVA中的内存地址,V),旧的预期值(A)和新值(B)。CAS执行时,当且仅当V符合预期A的时候,新值更新V的值,否则不执行更新,但是最终都会返回V的旧值,上述的处理过程就是一个原子操作。 (图片来源网络) 比如:要将上图中的CPU1要将56更新为57

JDK8---UnSafe类实现CAS乐观锁

喜夏-厌秋 提交于 2020-12-04 00:54:09
CAS:CompareAndSwap(比较并交换),简单点说,内存地址V,旧值为A,当要修改为新值B的时候,先判断V当前的值是不是A,如果是,则将V的值修改为B,否则失败。 那么JDK8中是怎么实现的呢?(ConCurrentHashMap、Atomic等常见线程安全类的底层实现都有它) 在sun.misc包下有一个 UnSafe类(在rt.jar包下面): public final class Unsafe { private Unsafe() { } public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } } } 构造方法私有,压根不让用。唯一暴漏的getUnsafe方法也不能使用。通过Reflection.getCallerClass() 拿到当前调用方法的实际类,从下面代码可以看到只要实际类的类加载器不为null,直接抛异常。因为rt.jar是由 bootstrap类加载器 来加载的,在Java中看不到的(null)

面试字节跳动Java一面问题基本都答对了,邮件通知被刷了,hr回复原因竟然是...

拈花ヽ惹草 提交于 2020-12-03 13:10:49
简介 面试是上海的Java岗位,周日一轮面试,自我感觉答的都还不错。 结果收到邮件面试结束了,说什么"你优秀的学识和能力给我们留下了深刻的印象!经过对你综合情况的仔细评估,并经过与岗位需求进行谨慎匹配和权衡之后, 非常遗憾,我们这次没有和你达成合作。但你的信息已经被录入到公司人才库"。意思就是挂了呗。 后来打电话问hr,说是我擅长的技术不是他们所需要的,???(黑人问号)。然后面试过程中,有一点奇怪的地方,面试前面试官跟我说我面的而这个岗位有点奇怪,他也没跟我说哪奇怪。 本文分享给需要面试刷题的朋友,另外本人也整理了一份资料包含了Java基础,数据结构,jvm,Redis,并发多线程,分布式,数据库等等,由于篇幅有限,以下只展示小部分面试题,有需要的朋友可以点击进群 795983544 领取,暗号CSDN 面试官的问题: 1.自我介绍 2.介绍印象深刻的项目,我介绍的是最新在做的项目,用到的技术,自己做的哪些模块? 回答:讲了用到的设计模式——模版方法,然后讲了模式方法的实现 3.因为最新的项目用到了,问了Spring Boot,Spring的区别? 回答:去配置化话,然后其他的基本一样,顺便说了一下Spring MVC的原理 4.Spring 的 bean是什么?我说了IOC、DI、Bean之间的关系 5.Hibernate 和 Mybatis的区别? 6

深入并发锁,解析Synchronized锁升级

本秂侑毒 提交于 2020-12-03 11:54:29
这篇文章分为六个部分,不同特性的锁分类,并发锁的不同设计,Synchronized中的锁升级,ReentrantLock和ReadWriteLock的应用,帮助你梳理 Java 并发锁及相关的操作。 一、锁有哪些分类 一般我们提到的锁有以下这些: 乐观锁/悲观锁 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面分别说明。 1、乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用。 (1)乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。 乐观锁适用于多读的应用类型,乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。 CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。 简单来说,CAS算法有3个三个操作数:

深入解析Linux并发同步

倖福魔咒の 提交于 2020-12-03 11:35:57
并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理多个任务的能力。并发和并行看起来很像,但实际上是有区别的,如下图: 上图的意思是,有两条在排队买咖啡的队列,并发只有一架咖啡机在处理,而并行就有两架的咖啡机在处理。咖啡机的数量越多,并行能力就越强。 linux内核的相关视频: 深度详解Linux内核网络结构及分布 epoll的具体实现与epoll线程安全|互斥锁|自旋锁|原子操作|CAS 手把手带你实现一个Linux内核文件系统 可以把上面的两条队列看成两个进程,并发就是指只有单个CPU在处理,而并行就有两个CPU在处理。为了让两个进程在单核CPU中也能得到执行,一般的做法就是让每个进程交替执行一段时间,比如让每个进程固定执行 100毫秒,执行时间使用完后切换到其他进程执行。而并行就没有这种问题,因为有两个CPU,所以两个进程可以同时执行。如下图: 【文章福利】小编推荐自己的C/C++Linux群:812855908!整理了一些个人觉得比较好的学习书籍、视频资料共享在里面,有需要的可以自行添加哦!~ 原子操作 上面介绍过,并发有可能会打断当前执行的进程,然后替切换成其他进程执行。如果有两个进程同时对一个共享变量 count 进行加一操作,由于C语言的 count++ 操作会被翻译成如下指令: mov eax , [ count ] inc eax mov