1、 背景

  传统Synchronized锁:悲观,如果没有获取到锁的情况下,会让当前线程变为阻塞的状态,释放CPU执行权,效率非常低。

  乐观锁(自旋):本质上没有锁,没有死锁现象,而且效率比较高,不会释放CPU执行权,自旋并通过预值比较或版本号控制。

2、原理

  CAS的英文全称是CompareAndSet,也就是比较然后修改,涉及到三个值,V、E和N,V是主内存的共享变量值,E是工作内存的副本值,N是修改内存的值。关于内存值的修改,有两种情况:第一种情况是比较V和E的值,如果相等,则对V进行修改;第二种情况是V和E不等,说明有线程已经修改过了,那就重新读取主内存的值,再做判断、修改。
V=内存值(主内存值);E=预期值(工作内存值) ;N=新值(需要修改的值)
  第一种情况:(V未被修改)
    第一步:读取主内存值V,复制给E
    第二步:判断V的值,如果V==E,说明共享变量的V没有被修改
    第三步:将V的值改为N
  第二种情况:(V被修改)
    第一步:读取内存之V,复制给E
    第二步:判断V的值,如果V!=E,说明别的线程修改了共享变量的V
    第三步:重新读取主内存V的值给E
    第四步:修改时再判断V的值是否等于E,如果不等,继续自旋,直至相等再将V的值修改为N。

  注意:不可能有两个线程同时修改V的值,因为CAS底层通过指令控制了原子性。

3、应用场景

  Java UNSAFE类
  原子类 Atomic

4、利用CAS原子类方式实现一个锁

 1 public class AtomicTryLock {
2
3 /**
4 * 定义AtomicInteger 修改为1表示该锁已经被使用该 修改为0表示为被使用
5 */
6 private volatile AtomicInteger atomicInteger = new AtomicInteger(0);
7 private Thread lockCurrentThread;
8
9 /**
10 * 尝试获取锁
11 *
12 * @return
13 */
14 public boolean tryLock() {
15 boolean result = atomicInteger.compareAndSet(0, 1);
16 if (result) {
17 lockCurrentThread = Thread.currentThread();
18 }
19 return result;
20 }
21
22 /**
23 * 释放锁
24 *
25 * @return
26 */
27 public boolean unLock() {
28 if (lockCurrentThread != null && lockCurrentThread != Thread.currentThread()) {
29 return false;
30 }
31 return atomicInteger.compareAndSet(1, 0);
32 }
33
34 public static void main(String[] args) {
35 AtomicTryLock atomicTryLock = new AtomicTryLock();
36 IntStream.range(1, 10).forEach((i) -> new Thread(() -> {
37
38 try {
39 boolean result = atomicTryLock.tryLock();
40 if (result) {
41 System.out.println(Thread.currentThread().getName() + ",获取锁成功~");
42 } else {
43 System.out.println(Thread.currentThread().getName() + ",获取锁失败~");
44 }
45 } catch (Exception e) {
46 e.printStackTrace();
47 atomicTryLock.unLock();
48 } finally {
49 atomicTryLock.unLock();
50 }
51
52 }).start());
53 }
54 }

5、如何解决CAS产生的ABA问题

5.1 什么是ABA问题

  如果【线程1】将原来的值A,改为了B,【线程2】将B又改为了A 发现没有发生变化,实际上已经发生了变化,但是【线程3】修改时判断V值没有发生变化,这种现象为ABA。

5.2 解决办法

  通过版本号码,对每个变量更新的版本号码做+1

来源:蚂蚁课堂(mayikt.com)

CAS无锁机制的更多相关文章

  1. CAS无锁机制原理

    原子类 java.util.concurrent.atomic包:原子类的小工具包,支持在单个变量上解除锁的线程安全编程 原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读 ...

  2. 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁

    1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...

  3. Atitit。Cas机制 软件开发 编程语言 无锁机制 java c# php

    Atitit.Cas机制 软件开发 编程语言 无锁机制 java c# php 1. 为什么需要无锁操作1 2. 硬件支持 cas  atomic2 3. 无锁编程(Lock-Free)就是在某些应用 ...

  4. (转载)java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  5. CAS无锁算法与ConcurrentLinkedQueue

    CAS:Compare and Swap 比较并交换 java.util.concurrent包完全建立在CAS之上的,没有CAS就没有并发包.并发包借助了CAS无锁算法实现了区别于synchroni ...

  6. java并发:AtomicInteger 以及CAS无锁算法【转载】

    1 AtomicInteger解析 众所周知,在多线程并发的情况下,对于成员变量,可能是线程不安全的: 一个很简单的例子,假设我存在两个线程,让一个整数自增1000次,那么最终的值应该是1000:但是 ...

  7. CAS 无锁式同步机制

    计算机系统中,CPU 和内存之间是通过总线进行通信的,当某个线程占有 CPU 执行指令的时候,会尽可能的将一些需要从内存中访问的变量缓存在自己的高速缓存区中,而修改也不会立即映射到内存. 而此时,其他 ...

  8. 无锁机制----比较交换CAS Compare And Swap

    一.锁与共享变量 加锁是一种悲观的策略,它总是认为每次访问共享资源的时候,总会发生冲突,所以宁愿牺牲性能(时间)来保证数据安全. 无锁是一种乐观的策略,它假设线程访问共享资源不会发生冲突,所以不需要加 ...

  9. CAS无锁技术

    前言:关于同步,很多人都知道synchronized,Reentrantlock等加锁技术,这种方式也很好理解,是在线程访问的临界区资源上建立一个阻塞机制,需要线程等待 其它线程释放了锁,它才能运行. ...

  10. CAS无锁实现原理以及ABA问题

    CAS(比较与交换,Compare and swap) 是一种有名的无锁算法.无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(N ...

随机推荐

  1. Flink Application Development DataStream API Event Time--Flink应用开发DataStream API事件时间

    目录 概览 事件时间 接下来去哪儿 水印生成 水印策略简介 使用水印策略 处理空闲源 写水印生成代码 写周期WatermarkGenerator代码 写符号形式的WatermarkGenerator代 ...

  2. Day 22 22.2:scrapy部署

    scrapy项目部署 scrapyd部署工具介绍 scrapyd是一个用于部署和运行scrapy爬虫的程序,它由 scrapy 官方提供的.它允许你通过JSON API来部署爬虫项目和控制爬虫运行. ...

  3. string转JSONObject顺序不变和 往map放数据按顺序

    JSONObject field = JSONObject.parseObject(fieldStr,Feature.OrderedField); Map<String,String> m ...

  4. fabric学习笔记3

    fabric学习笔记3 20201303张奕博 2023.1.11 Hyperledger Fabric架构设计 分布式帐本 区块链核心概念是分布式帐本,就像下面的图1所示,同样的帐本(全量的交易数据 ...

  5. es6数组去重、数组中的对象去重 && 删除数组(按条件或指定具体元素 如:id)&& 筛选去掉没有子组件的父组件

    // 数组去重 { const arr = [1,2,3,4,1,23,5,2,3,5,6,7,8,undefined,null,null,undefined,true,false,true,'中文' ...

  6. jquery 事件方法大全

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <style type ...

  7. docker 清除redis缓存

    1.仓库容器id: docker  ps 2.进入容器:docker exec -it 容器id  redis-cli 3.清除所有缓存:flushall

  8. 1、PyTorch基本操作

    一.简介 简单介绍PyTorch框架,基本使用和安装方法.Torch是什么?一个火炬!其实跟Tensorflow中Tensor是一个意思,就是说,有一批数据,无论是图像数据还是文本数据或数值数据,都需 ...

  9. 11.20 dom 浏览器对象模型

    1.window.open(url,ways) url 是打开的网页地址 ways 打开的方式 _self 2.window.close() 3.浏览器用户信息:Window.navigator 4. ...

  10. python 读取ini文件内容

    1 import configparser 2 cfgini = "D:\\123.ini" 3 conf = configparser.ConfigParser() 4 conf ...