CAS和Synchronized知识

一. CAS

何为CAS。

CAS(Compare And Swap )是乐观锁的一种实现方式,是一种轻量级锁。JAVA1.5开始引入了CAS,JUC下很多工具类都是基于CAS。

在这里插入图片描述

CAS的实现方式

CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。当多个线程同时尝试使用CAS更新一个变量时,任何时候只有一个线程可以更新成功,若更新失败,线程会重新进入循环再次进行尝试。

img

CAS在Java中的应用

前面也说了JUC下面很多工具类都用到了CAS。其主要依赖于Unsafe的CAS操作来进行实现。
例如AtomicInteger下的incrementAndGet操作:

在这里插入图片描述

接着来看看Unsafe下的getAndAddInt方法

在这里插入图片描述

可以看到Unsafe中在循环体内先读取内存中的value值,然后CAS更新,如果CAS更新成功则退出,如果更新失败,则循环重试直到更新成功。

CAS带来的问题

ABA问题

例如说:
一. 线程1查询值是否为A
二. 线程2查询值是否为A
三. 线程2使用CAS将值更新为B
四. 线程2查询值是否为B
五. 线程2使用CAS将值更新为A
六. 线程1使用CAS将值更新为C
线程一线程二交替执行。第二步到第五步,线程二将值由A更新为B由更新为A,但线程一并没有察觉,因此线程一还是可以继续执行。我们称这种现象为ABA问题。
解决方法:
使用版本号 (时间戳),在每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号加一,否则就执行失败。例如AtomicStampedReference就是通过对值加一个戳(stamp)来解决“ABA”问题的。

循环开销过大

CAS操作不成功的话,会导致一直自旋,CPU的压力会很大。例如说Unsafe下的getAndAddInt方法会一直循环,直到成功才会返回。

只能保证一个变量的原子操作

二. synchronized

相比于CAS基于乐观锁实现,synchronized是基于悲观锁的,当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

对于普通同步方法加锁时,锁是当前实例对象。

对于静态同步方法加锁时,锁是当前类的Class对象。

对于同步方法块加锁时,锁是Synchonized括号里配置的对象。

Synchronized的实现方式:
Synchonized是基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。Synchronized 用在方法上时,在字节码中是通过方法的 ACC_SYNCHRONIZED 标志来实现的。而代码块同步则是使用monitorenter和monitorexit指令实现的。
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁,当获得对象的monitor以后,monitor内部的计数器就会自增(初始为0),当同一个线程再次获得monitor的时候,计数器会再次自增。当同一个线程执行monitorexit指令的时候,计数器会进行自减,当计数器为0的时候,monitor就会被释放,其他线程便可以获得monitor。

Synchronized的优化
Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,在Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。

偏向锁
当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁),如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

轻量级锁
线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

重量级锁
重量级锁是依赖对象内部的monitor锁来实现。当系统检查到锁是重量级锁之后,会把等待想要获得锁的线程进行阻塞,被阻塞的线程不会消耗cup。但是阻塞或者唤醒一个线程时,都需要操作系统来帮忙,需要从用户态转换到内核态,而转换状态是需要消耗很多时间。

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动设置图片的序号_编写学位论文时如何给表格和图片自动编号

引言最近和论文格式的检测系统斗智斗勇,可以说是摸清了系统的脾气并且能够把错误数控制在0。其中,论文正文的表格和图片自动编号的问题还是挺有意思的,特此记录一下。需求对于表格,系统要求表格题注处于表格*上方*,并按…

使用CAS代替synchronized

在开发当中需要经常用到synchronized保证代码线程安全,在竞争条件下会阻塞等待资源,如果允许竞争不到资源返回失败,就可以使用cas减少阻塞时间。先来看一个cas的单例模式。 public class NonBlock {private static volatile NonBlock nonBlo…

uniapp 获取图片的高度_uni-app获取元素高度等信息,并设置元素top信息

本文主要简介uni-app获取元素信息及设置信息等获取元素高度可查看官方文档mounted() {const query uni.createSelectorQuery().in(this);query.select(#editor).boundingClientRect(data > {console.log(data)}).exec();},这里的data用于获取这个元素大小及位置信息&#x…

关于java中线程yield()方法问题

关于java中线程yield()方法问题 问题一: 我知道yield是用来休眠当前线程,但我查看了资料,又说其不会释放锁,所以我就不解了,其明明会将cpu资源给其他线程,那它不释放锁,其他线程有怎么获取cpu资…

Lisp尺寸标注增加前后缀_求一CAD标注加前缀与后缀lisp

回答:1.计算所有线段总长度(加载后只需框选所有线段便可得出这些线段的总长度)(defun c:LL ()(setvar "cmdecho" 1)(setq en (ssget(list (0 . "spline,arc,line,ellipse,LWPOLYLINE"))))(setq i 0)(setq ll 0)(repeat (sslength en)(setq ss (…

beetl 页面标签_05.Beetl标签函数以及定界符、占位符介绍---《Beetl视频课程》

标签函数 layout所谓标签函数,即允许处理模板文件里的一块内容,功能等于同jsp tag。如Beetl内置的layout标签index.htmllayout("/inc/layout.html",{title:主题}){%>Hello,this is main partlayout.htmltitle is ${title}body content ${la…

hql实例 jpa_SpringBoot学习笔记九:Spring Data Jpa的使用

Spring Data Jpa 简介JPAJPA(Java Persistence API)意即Java持久化API,是Sun官方在JDK5.0后提出的Java持久化规范(JSR 338,这些接口所在包为javax.persistence,详细内容可参考https://github.com/javaee/jpa-spec)JPA的出现主要是为了简化持久…

Objects.requireNonNull 方法说明

在写代码的时候,Idea经常会提醒我们可以使用这个方法来进行参数非空检查, 这个方法的源码也非常简单, 如下所示: /*** Checks that the specified object reference is not {code null}. This* method is designed primarily for doing parameter validation in methods* and …

Java service层获取HttpServletRequest工具类的方法

大家都知道 能在Controller/action层获取HttpServletRequest ,但是这里给大家备份的是从代码内部service层获取HttpServletRequest工具类。 具体如下: package com.base.common.sessionutils; import javax.servlet.http.HttpServletRequest; import j…

正则表达式发明者_浅谈正则表达式背后的基本原理

一、写在前面搞编程的都知道正则表达式是什么东西,这里就不多啰嗦了,需要强调的是,这篇文章并不是教你怎么去使用用正则表达式,正则表达式的语法并不是本文的重点,这篇文章的目的就是剥开正则表达式的语法糖&#xff0…

Java8 - 使用 Comparator.comparing 进行排序

使用外部比较器Comparator进行排序 当我们需要对集合的元素进行排序的时候,可以使用java.util.Comparator 创建一个比较器来进行排序。Comparator接口同样也是一个函数式接口,我们可以把使用lambda表达式。如下示例, package com.common;im…

cairo填充_Cairo 图形指南 (5) —— 形状与填充

这一部分,讲述一些基本的以及较为高级的形状绘制及其纯色 (solid color)、图案 (pattern) 与渐变 (gradient) 填充方法。基本形状Cairo 提供了几个用于绘制基本形状的函数。#include#include#includestatic gbooleanon_expose_event (GtkWidget * widget,GdkEventEx…

java集合进行排序的两种方式

java集合的工具类Collections中提供了两种排序的方法,分别是: Collections.sort(List list)Collections.sort(List list,Comparator c) 第一种称为自然排序,参与排序的对象需实现comparable接口,重写其compareTo()方法,方法体中实现对象的比较大小规则,示例如下: 实体类:(基本…

ubuntu编写python脚本_python在ubuntu中的几种方法(小结)

通过ubuntu官方的apt工具包安装通过PPA(Personal Package Archive) 的apt工具包安装通过编译python源代码安装通过ubuntu官方的apt工具包安装安装完成后, 可以用下面的命令进行确认从PPA(Personal Package Archives) 安装apt工具包类似使用apt工具包安装python的工…

Java中String类中compareTo( )方法

compareTo方法是比较简单的,我们可以直接看其源码: 源码如下: public int compareTo(String anotherString) {int len1 value.length;int len2 anotherString.value.length;int lim Math.min(len1, len2);char v1[] value;char v2[] anotherString…

python elif可以单独使用_Python的elif语句怎么用

else和elif语句也可以叫做子句,因为它们不能独立使用,两者都是出现在if、for、while语句内部的。else子句可以增加一种选择;而elif子句则是需要检查更多条件时会被使用,与if和else一同使用,elif是else if 的简写。if和…

SpringMVC接收哪些类型参数参数

支持的数据类型: 基本类型参数: 包括基本类型和 String 类型 POJO 类型参数: 包括实体类,以及关联的实体类 数组和集合类型参数: 包括 List 结构和 Map 结构的集合(包括数组) SpringMVC …

禁用当前的账户win7_系统小技巧:服务客人 开启Windows 10来宾账户

出于安全考虑,Windows 10默认以管理员账户登录,没有开启来宾账户。但对于那些只需在电脑上浏览网页或收看电子邮件的用户,给他们开启来宾账户非常必要。来宾权限或账户的开启,可以通过下面的两种方法。1. 通过系统设置 开启来宾权…

Java之接口的静态方法的定义和使用

格式如下:(就是将abstract或者default换成ststic即可,带上方法体) public static 返回值类型 方法名称(参数列表){方法体----}代码如下: //定义一个接口 public interface MyInterfaceStatic …

三阶魔方还原步骤图_三阶魔方公式图解、教程

三阶魔方公式、魔方图解、魔方教程,从零基础到精通!魔方还原法 Rubics Cube Solution ————先看理论“魔方的还原方法很多精彩内容,尽在百度攻略:https://gl.baidu.com在这里向大家介绍一种比较简单的魔方六面还原方法。这种方…