JUC之CAS比较并交换

news2024/11/19 7:48:20

CAS

原子类引入
在这里插入图片描述
加入原子整型类的操作后,无锁化的操作
在这里插入图片描述
CAS 比较并交换
在这里插入图片描述
在这里插入图片描述
硬件级别的保证
在这里插入图片描述
源码分析
在这里插入图片描述
引出UnSafe类
在这里插入图片描述
在这里插入图片描述
UnSafe源码分析
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
unsafe中的do-while保证自旋

  public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
      var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
  }

在这里插入图片描述

CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题
在这里插入图片描述
native修饰的方法代表的是底层的方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
CAS是靠硬件实现的,从而在硬件层面提升效率。最底层还是交给硬件来保证原子性和可见性。实现方式是基于硬件平台的汇编指令,在intel的CPU中(X86机器上),使用的是汇编指令cmpxchg指令。
核心思想就是:比较要更新变量的值V和预期值E(compare),相等才会将V的值设为新值N(swap),如果不相等自旋再来。

原子引用

public class TestAutomicReference {


  @ToString
  @Data
  @AllArgsConstructor
  static class Use{
    private String name;
    private int age;
  }

  public static void main(String[] args) {
    AtomicReference<Use> useAtomicReference = new AtomicReference<>();
    Use lisi = new Use("lisi", 10);
    useAtomicReference.set(lisi);
    Use zhangsan = new Use("zhangsan", 12);
    boolean b = useAtomicReference.compareAndSet(lisi, zhangsan);
    System.out.println("result:"+b+"\t\t"+useAtomicReference.get());
  }
}

CAS与自旋锁,借鉴CAS思想

自旋锁
在这里插入图片描述
在这里插入图片描述
手写自旋锁demo

package com.aiguigu.juclearn.atomic;

/**
 * @author: Runqiang_Jiang
 * @Time: 2024/3/16  11:55
 */

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 题目:实现一个自旋锁
 * 自旋锁的好处:循环比较获取,没有类似wait的阻塞
 * 通过CAS操作完成自旋锁,A线程先进来调用myLock方法自己持有锁5秒钟,
 * B随后进来后发现当前有线程持有锁,所以只能通过自旋等待,知道啥A释放锁后B随后抢到
 */
public class SpinLockDemo {

  AtomicReference<Thread> atomicReference=new AtomicReference<>();

  public  void lock(){
    Thread thread = Thread.currentThread();

    System.out.println(Thread.currentThread().getName()+"\t"+"------come in");

    while (!atomicReference.compareAndSet(null, thread)) {

    }

  }

  public void unlock(){
    Thread thread = Thread.currentThread();

    atomicReference.compareAndSet(thread,null);
    System.out.println(Thread.currentThread().getName()+"\t"+"-----task over unlock");

  }

  public static void main(String[] args) throws InterruptedException {

    SpinLockDemo spinLockDemo = new SpinLockDemo();

     new Thread(()->{
       spinLockDemo.lock();
       //暂停几秒钟
       try {
         TimeUnit.SECONDS.sleep(5);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       spinLockDemo.unlock();
     },"A").start();

     //暂停500毫秒,线程A先于线程B启动
     TimeUnit.MILLISECONDS.sleep(500);


    new Thread(()->{
      spinLockDemo.lock();
      spinLockDemo.unlock();
    },"B").start();
  }

}

在这里插入图片描述
CAS的两大缺点
1.循环时间长开销很大
在这里插入图片描述
2.引出来ABA问题???
在这里插入图片描述
解决方案:版本号时间戳原子引用
demo演示

package com.aiguigu.juclearn.atomic;

import java.util.concurrent.atomic.AtomicStampedReference;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author: Runqiang_Jiang
 * @Time: 2024/3/16  12:18
 */

@AllArgsConstructor
@NoArgsConstructor
@Data
class  Book{
  private int id;
  private String bookName;
}



public class AtomicStampedDemo {


  public static void main(String[] args) {

    Book java = new Book(1, "java");

    AtomicStampedReference<Book> stampedReference=new AtomicStampedReference<>(java,1);

    System.out.println(stampedReference.getReference()+"\t"+stampedReference.getStamp());

    Book mysql = new Book(2, "mysql");

    boolean b ;
        b= stampedReference.compareAndSet(java, mysql, stampedReference.getStamp(),
        stampedReference.getStamp() + 1);

    System.out.println(b+"\t"+stampedReference.getReference()+"\t"+stampedReference.getStamp());

    b= stampedReference.compareAndSet(mysql, java, stampedReference.getStamp(),
        stampedReference.getStamp() + 1);

    System.out.println(b+"\t"+stampedReference.getReference()+"\t"+stampedReference.getStamp());

  }
}

ABA后版本号有变化
在这里插入图片描述
ABA多线程demo

package com.aiguigu.juclearn.atomic;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author: Runqiang_Jiang
 * @Time: 2024/3/16  12:31
 */

public class ABADemo {


  static AtomicInteger atomicInteger = new AtomicInteger(100);

  static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,1);

  public static void main(String[] args) {

    new Thread(()->{
      int stamp = stampedReference.getStamp();
      System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号:"+stamp);
      //休眠保证后面的t4线程拿到的版本号与t3一样
      try {
        TimeUnit.MILLISECONDS.sleep(500);
      } catch (InterruptedException e) {

      }
      stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()+1);
      System.out.println(Thread.currentThread().getName()+"\t"+"2次版本号:"+stampedReference.getStamp());


      stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()+1);
      System.out.println(Thread.currentThread().getName()+"\t"+"3次版本号:"+stampedReference.getStamp());
    },"t3").start();

    new Thread(()->{
      int stamp = stampedReference.getStamp();
      System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号:"+stamp);
      //等待t3线程发生了ABA的问题
      try {
        TimeUnit.SECONDS.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

      boolean b = stampedReference.compareAndSet(100, 2024, stamp, stamp + 1);


      System.out.println(b+"\t"+Thread.currentThread().getName()+"\t"+stampedReference.getReference()+"\t"+stampedReference.getStamp());

    },"t4").start();

  }

  private static void abahappens() {
    new Thread(()->{
      atomicInteger.compareAndSet(100,101);
      try {
        TimeUnit.MILLISECONDS.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

      atomicInteger.compareAndSet(101,100);


    },"t1").start();

    new Thread(()->{
      try {
        TimeUnit.MILLISECONDS.sleep(200);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      boolean b = atomicInteger.compareAndSet(100, 2024);
      System.out.println(b+"\t"+atomicInteger.get());
    },"t2").start();
  }

}

版本号不一致,t4线程没有修改成功
在这里插入图片描述

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

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

相关文章

Linux:kubernetes(k8s)有状态的服务部署(14)

之前我都是对无状态进行的一个操作&#xff0c;我们想扩容就扩容&#xff0c;想缩容就缩容&#xff0c;根本不用去考虑他的一个网络环境&#xff0c;本地储存环境啥的一个状态 当我们做有状态的服务的操作&#xff0c;肯定要申请一个持久化的一个空间&#xff0c;以及网络&…

Linux环境(Ubuntu)上的防火墙工具使用方法

目录 概述 1 防火墙工具&#xff08;ufw&#xff09; 1.1 安装防火墙工具&#xff1a; 1.2 操作防火墙相关命令 2 ufw操作命令的范例 2.1 打开/关闭防火墙 2.1.1 打开防火墙 2.1.2 关闭防火墙 2.1.3 查询当前防火墙状态 2.1.4 允许选择的端口访问 2.1.5 允许选择固定…

自动写作软件哪个好?分享7款独家推荐

随着人工智能技术的不断发展&#xff0c;自动写作软件正逐渐成为现代写作的利器。这些AI写作工具能够帮助用户高效地生成文章、报告、新闻稿等内容&#xff0c;为写作工作带来了极大的便利。然而&#xff0c;市面上的自动写作软件琳琅满目&#xff0c;让人眼花缭乱。为了帮助读…

SpringCloud返回的是xml格式而非JSON数据

一、问题描述&#xff1a; 最近接触eureka&#xff0c;写了一个接口&#xff0c;使用RestController注解修饰了类&#xff0c;预期是返回json格式的数据&#xff0c;但是结果返回的是xml格式的数据。 二、问题分析&#xff1a; 原因是因为直接或间接引入了jackson-dataformat…

相机拍照与摄影学基础

1.相机拍照 相机可能形状和大小不同&#xff0c;但基本功能相同&#xff0c;包括快门速度、光圈和景深&#xff0c;这些是摄影的通用概念。即使是一次性相机也是基于这三个理念工作的。不同类型相机在这三个概念上的唯一区别是你可以控制这些功能的程度。这三个参数被称为相机…

mybatis+thymeleaf登录

目录 一.将页面显示在浏览器中 1.新建项目并导入页面 2.使用th标签 3.新建控制层 4.显示结果 二.将两个页面进行关联 1.提交表单 2.跳转页面 3.结果 三.登录账号名动态改变 1.获取登录表单数据 2.给页面传值 3.页面显示 4.结果 四.连接数据库 1.新建数据库 2.…

tcp/ip协议2实现的插图,数据结构8 (30 - 32章)

(201) 201 三十0 中断优先级补充 (202) 202 三十1 TCP的用户需求 函tcp_usrreq一 (203) 203 三十2 TCP的用户需求 函tcp_usrreq二 (204) 204 三十3 TCP的用户需求 函tcp_usrreq三 (205) 205 三十4 TCP的用户需求 函tcp_usrreq四 (206) 206 三十5 TCP的用户需求 函tcp_usrreq五 …

C语言 内存函数

目录 前言 一、memcpy()函数 二、memmove()函数 三、memset函数 四、memcmp()函数 总结 前言 在C语言中内存是我们用来存储数据的地址&#xff0c;今天我们来讲一下C语言中常用的内存函数。 一、memcpy()函数 memcpy()函数与我们之前讲的strcpy()函数类似&#xff0c;只…

[SAP ABAP] 创建事务码T-CODE

如何让用户通过输入事务码T-CODE跳转到Z437_TEST_2024程序输出界面&#xff1f; 1.输入事务码SE39&#xff0c;进入到维护事务的界面 2.输入需要创建的事务码名称(一般情况下用Y或者Z开头)&#xff0c;点击【创建】 这里我们创建一个名为ZTEST437的事务代码 3.在创建事务的窗口…

springboot爱看漫画小程序的设计与实现

摘 要 相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低爱看漫画的运营人员成本&#xff0c;实现了爱看漫画的标准化、制度化、程序化的管理&#xff0c;有效地防止了爱看漫画的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时、…

leetcode代码记录(子集

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集 &#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 …

MySQL MHA故障切换

目录 一、案例分析 1.1、案例概述 1.2、案例前置知识点 1&#xff09;什么是 MHA 2&#xff09;MHA 的组成 3&#xff09;MHA 的优势 4&#xff09;MHA 现状 1.3、案例环境 1&#xff09;本案例环境 ​编辑 2&#xff09;案例需求 3&#xff09;案例实现思路…

解读如何打造超高商楼宇智慧公厕

智慧楼宇大厦智慧公厕是近年来兴起的一个创新方案&#xff0c;旨在为现代城市的楼宇建筑提供一种全新的管理与服务模式。这种智慧公厕的最大特点就是将智能化技术与传统楼宇公厕结合&#xff0c;通过各种高科技设备与系统&#xff0c;实现对公厕的全新管理与监控&#xff0c;为…

java serlvet 高校学生画像平台系统Myeclipse开发mysql数据库web结构java编程计算机网页项目echarts图形展现

一、源码特点 java serlvet 高校学生画像平台系统是一套完善的java web信息管理系统 系统采用serlvetdaobean 模式开发本系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCA…

Jmeter+Ant 接口自动化环境配置指南

一 、Jmeter安装与配置 https://blog.csdn.net/tester_sc/article/details/80746405 注&#xff1a;Jmeter5.0的环境变量配置与4.0或历往老版本有部分小差异&#xff0c;笔者用的Jmeter 5.0 二 、Ant的安装与配置 # Ant下载地址(下载到指定目录后&#xff0c;进行解压到当前…

Spark-Transformation以及Action开发实战

文章目录 创建RDDTransformation以及ActionTransformation开发Action开发RDD持久化共享变量创建RDD RDD是Spark的编程核心,在进行Spark编程是,首要任务就是创建一个初始的RDDSpark提供三种创建RDD方式:集合、本地文件、HDFS文件 集合:主要用于本地测试,在实际部署到集群运…

电路方案分析(十八)四开关buck-boost双向同步DC/DC变换器方案

tip是&#xff1a;资料来自网络&#xff0c;仅供学习交流使用&#xff01; 1.概述 4开关降压升压双向DC-DC电源转换器在很多应用中都有使用。作为一个同步降压或同步升压转换器&#xff0c;其中只有两个开关切换&#xff0c;开关损耗减少到一半。只有当直流母线和电池电压彼此…

【MMDetection3D实战5】Dataset 和 model配置文件解析

文章目录 1. Dataset 配置文件解析1. 1 定义全局变量1. 1 数据处理pipeline(1) train_pipeline(2) test_pipeline(3) eval_pipeline1. 2 data 字典的定义2. model 配置文件解析2. 1 体素化voxel_layer2. 2 voxel_encoder2. 3 middle_encoder2. 4 2D 检测网络(backbone + neck …

C++实验 面向对象编程

一、实验目的&#xff1a; 掌握类中静态成员的定义方法&#xff0c;初始化方法&#xff0c;使用方法&#xff1b; 掌握类的友元说明方法&#xff0c;理解友元的使用特点 二、实验内容&#xff1a; 1、编写程序&#xff0c;统计某旅馆住宿客人的总数&#xff0c;要求输入客人…

hot100 -- 矩阵

&#x1f442; Peter Pan - kidult. - 单曲 - 网易云音乐 &#x1f442; Bibliothque&#xff08;图书馆&#xff09; - Jasing Rye - 单曲 - 网易云音乐 目录 &#x1f33c;前言 &#x1f33c;二分模板 &#x1f382;矩阵置零 AC 标记数组 AC 标记变量 &#x1f6a9;…