java JUC并发编程 第六章 CAS

这篇具有很好参考价值的文章主要介绍了java JUC并发编程 第六章 CAS。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录

第一章 java JUC并发编程 Future: link
第二章 java JUC并发编程 多线程锁: link
第三章 java JUC并发编程 中断机制: link
第四章 java JUC并发编程 java内存模型JMM: link
第五章 java JUC并发编程 volatile与JMM: link
第六章 java JUC并发编程 CAS: link
第七章 java JUC并发编程 原子操作类增强: link
第八章 java JUC并发编程 ThreadLocal: link
第九章 java JUC并发编程 对象内存布局与对象头: link
第十章 java JUC并发编程 Synchronized与锁升级: link
第十一章 java JUC并发编程 AbstractQueuedSynchronizer之AQS: link



1 概述

了解原子类:java.util.concurrent.atomic 下面所有相关的类和api的调用

1.1 没有CAS之前多线程环境不使用原子类保证线程安全i++(基本数据类型)

java JUC并发编程 第六章 CAS,java,开发语言

1.2 使用cas之后多线程环境使用原子类保证线程安全i++

java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言
两者的区别AtomicInteger要比加了synchronized的重量级锁性能更好。
类似乐观锁

2 CAS是什么

java JUC并发编程 第六章 CAS,java,开发语言

2.1 CAS原理

java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言

2.1.1 例

package com.atguigu.springcloud.util.interrup;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(5);
        //预期是5的时候才替换成2022
        System.out.println(atomicInteger.compareAndSet(5,2022)+" :"+ atomicInteger.get());
    }
}

java JUC并发编程 第六章 CAS,java,开发语言

2.1.2 unasfe类

this:当前对象
valueoffset:当前对象内存地址的偏移量
expect:期望值
update:更新值
java JUC并发编程 第六章 CAS,java,开发语言

2.1.3 硬件级别保证

java JUC并发编程 第六章 CAS,java,开发语言
AtomicInteger底层调用的是Unsafe类
java JUC并发编程 第六章 CAS,java,开发语言

2.1.4 UnSafe的理解

java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言
i++是线程不安全的,那atomiclnteger.getAndIncrement()就可以么
java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言
var1:this(当前对象)
var2:valueoffset
var5:当前对象最新值
如果对比成功让var5+var4(1)

2.1.5 UnSafe底层原理

2.1.5.1 getAndIncrement()

java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言

2.1.5.2 native修饰的方法代表是底层方法

java JUC并发编程 第六章 CAS,java,开发语言

2.1.5.3 compxchg

java JUC并发编程 第六章 CAS,java,开发语言

2.1.5.4 在不通的操作系统下会调用不同的cmpxchg重载函数

java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言

2.2 总结

CAS是靠硬件实现的从而在硬件层面提升效率,最底层还是交给硬件来保证原子性和可见性实现方式是基于硬件平台的汇编指令,在intel的CPU中(X86机器上),使用的是汇编指令cmpxchg指令。
核心思想是:比较要更新变量的值V和预期值E(compare),相等才会将V的值设为新值N(swap)如果不相等自旋再来。

3 原子引用

3.1 Atomiclnteger 其他原子类型

package com.atguigu.springcloud.util.interrup;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

import java.util.concurrent.atomic.AtomicReference;
@Getter
@ToString
@AllArgsConstructor
class User{
    String userName;
    int age;
}
public class AtomicReferenceDemo {
    public static void main(String[] args) {
        AtomicReference<User> atomicReference = new AtomicReference<>();
        User z3 = new User("z3",22);
        User li4 = new User("li4",28);

        atomicReference.set(z3);
        System.out.println(atomicReference.compareAndSet(z3,li4)+":"+atomicReference.get().toString());
    }


}

4 CAS与自旋锁

java JUC并发编程 第六章 CAS,java,开发语言
java JUC并发编程 第六章 CAS,java,开发语言

4.1 自己实现自旋锁

package com.atguigu.springcloud.util.interrup;

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

public class SpinLockDemo {
    AtomicReference<Thread> atomicReference = new AtomicReference<>();
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"come in");
        while (!atomicReference.compareAndSet(null,thread)){}
    }

    public void myUnlock(){
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+" invoked myUnLock()");
    }

    public static void main(String[] args) {
        //自己实现的自旋锁
        /**
         * 实现一个自旋锁
         * 自旋锁好处:循环比较获取没有类似wait的阻塞
         *
         * 通过cas操作来完成自旋锁,A线程先进来调用myLock方法自己持有锁5分钟,
         * B随后进来发现当前所有线程持有锁,所以只能通过自旋等待,直到A释放锁后B随后抢到。
         */
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(()->{
            spinLockDemo.myLock();
            System.out.println(Thread.currentThread().getName()+"正在干活");
            try{
                TimeUnit.SECONDS.sleep(10);}catch (InterruptedException e){e.printStackTrace();}
            spinLockDemo.myUnlock();
        },"AA").start();
        try{TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e){e.printStackTrace();}

        new Thread(()->{
            spinLockDemo.myLock();
            System.out.println(Thread.currentThread().getName()+"正在干活");
            spinLockDemo.myUnlock();
        },"BB").start();
    }
}

5 CAS的缺点

5.1 循环时间长导致cpu开销过大

java JUC并发编程 第六章 CAS,java,开发语言

5.2 引出ABA问题

java JUC并发编程 第六章 CAS,java,开发语言
解决:版本号时间戳原子引用

5.2.1 AtomicStampedReference简单case

package com.atguigu.springcloud.util.interrup;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.concurrent.atomic.AtomicStampedReference;

@NoArgsConstructor
@AllArgsConstructor
@Data
class Book{
    private int id;
    private String bookName;
}
public class AtomicStampedDemo {
    public static void main(String[] args) {
        Book javaBook = new Book(1,"javaBook");
        AtomicStampedReference<Book> stampedReference = new AtomicStampedReference<>(javaBook,1);
        System.out.println(stampedReference.getReference()+":"+stampedReference.getStamp());
        Book mysqlBook = new Book(2,"mysqlBook");
        //参数1:期望book 参数2:替换book 参数3:期望版本号  参数4:替换版本号
        boolean b;
        b = stampedReference.compareAndSet(javaBook,mysqlBook,stampedReference.getStamp(),stampedReference.getStamp()+1);
        System.out.println(b+"\t"+stampedReference.getReference()+":"+stampedReference.getStamp());

        //再换回去,增加了版本号的检查
        b = stampedReference.compareAndSet(mysqlBook,javaBook,stampedReference.getStamp(),stampedReference.getStamp()+1);
        System.out.println(b+"\t"+stampedReference.getReference()+":"+stampedReference.getStamp());

    }
}

java JUC并发编程 第六章 CAS,java,开发语言

5.2.2 AtomicInteger BAB问题复现

package com.atguigu.springcloud.util.interrup;

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

/**
 * 多线程下ABA问题
 */
public class ABADemo {
    static AtomicInteger atomicInteger = new AtomicInteger(100);
    public static void main(String[] args) {
        new Thread(()->{
            //改为101
            atomicInteger.compareAndSet(100,101);
            try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
            //再改回100 模拟ABA
            atomicInteger.compareAndSet(101,100);
        },"t1").start();


        //只检查内容忽略了B的操作
        new Thread(()->{
            try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println(atomicInteger.compareAndSet(100,202)+"\t"+atomicInteger.get());
        },"t2").start();

    }
}

5.2.3 AtomicStampedReference 版本号机制避免ABA

package com.atguigu.springcloud.util.interrup;

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

/**
 * 多线程下ABA问题
 */
public class ABADemo {
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号:"+stamp);
            //保证后面的t4线程拿到的版本号和这里一样
            try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
            atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t"+"2次版本号:"+ atomicStampedReference.getStamp());

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

        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t"+"首次版本号:"+stamp);

            //等待t3发生了ABA问题
            try {TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
            boolean b= atomicStampedReference.compareAndSet(100,2022,stamp,stamp+1);
            System.out.println(b+"\t"+atomicStampedReference.getReference()+"\t"+atomicStampedReference.getStamp());
        },"t4").start();

    }
}

结果:
java JUC并发编程 第六章 CAS,java,开发语言文章来源地址https://www.toymoban.com/news/detail-683682.html

到了这里,关于java JUC并发编程 第六章 CAS的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java 并发编程】CAS 原理解析

    悲观锁 的原理是每次实现数据库的增删改的时候都进⾏阻塞,防⽌数据发⽣脏读。 乐观锁 的原理是在数据库更新的时候,⽤⼀个 version 字段来记录版本号,然后通过⽐较是不是⾃⼰要修改的版本号再进⾏修改。这其中就引出了⼀种⽐较交换的思路来实现数据的⼀致性,事实

    2024年02月06日
    浏览(26)
  • Java——并发编程(CAS、Lock和AQS)

    答: Lock 接口比同步方法和同步块提供了 更具扩展性的锁操作 。他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的条件对象。 可以使锁更公平; 可以使线程在等待锁的时候响应中断; 可以让线程尝试获取锁,并在无法获取锁的时候立即返回或

    2024年02月06日
    浏览(38)
  • java JUC并发编程 第九章 对象内存布局与对象头

    第一章 java JUC并发编程 Future: link 第二章 java JUC并发编程 多线程锁: link 第三章 java JUC并发编程 中断机制: link 第四章 java JUC并发编程 java内存模型JMM: link 第五章 java JUC并发编程 volatile与JMM: link 第六章 java JUC并发编程 CAS: link 第七章 java JUC并发编程 原子操作类增强: link 第八章

    2024年02月07日
    浏览(28)
  • 【并发编程】JUC并发编程(彻底搞懂JUC)

    如果你对多线程没什么了解,那么从入门模块开始。 如果你已经入门了多线程(知道基础的线程创建、死锁、synchronized、lock等),那么从juc模块开始。 新手学技术、老手学体系,高手学格局。 JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称 ,其结构如下: 这个包

    2024年02月20日
    浏览(37)
  • redis第五第六章-redis并发缓存架构和性能优化

    缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中, 通常出于容错的考虑, 如果从存储层查不到数据则不写入缓存层。 缓存穿透将导致不存在的数据每次请求都要到存储层去查询, 失去了缓存保护后端存储的意义。 造成缓存穿透的基本原因有两个:

    2024年02月08日
    浏览(39)
  • Java多线程(3)---锁策略、CAS和JUC

    目录 前言 一.锁策略 1.1乐观锁和悲观锁 ⭐ 两者的概念 ⭐实现方法 1.2读写锁  ⭐概念 ⭐实现方法 1.3重量级锁和轻量级锁 1.4自旋锁和挂起等待锁 ⭐概念 ⭐代码实现 1.5公平锁和非公平锁 1.6可重入锁和不可重入锁 二.CAS 2.1为什么需要CAS 2.2CAS是什么 ⭐CAS的介绍 ⭐CAS工作原理

    2024年02月13日
    浏览(36)
  • 【并发编程】CAS到底是什么

    Java实现CAS的原理 | Java程序员进阶之路 美团终面:CAS确定完全不需要锁吗? CAS 是 Compare-And-Swap (比较并交换)的缩写,是一种 轻量级的同步机制 ,主要用于实现多线程环境下的无锁算法和数据结构,保证了并发安全性。它可以在 不使用锁 (如synchronized、Lock)的情况下,对

    2024年02月20日
    浏览(25)
  • Qt第六章 多窗口编程

    QMessageBox继承自QDialog ,是一个Qt内置的用来展示 信息或询问用户一个问题的模态对话框。 预设了四种类型: 像那些已经写好的窗口,这些现成的东西都会有一些特性,就是他们的对象都不需要new或者说他们就不需要拿到对象,他们为了方便我们使用会用一个静态成员函数就

    2024年02月07日
    浏览(23)
  • 【JUC并发编程】

    本笔记内容为狂神说JUC并发编程部分 目录 一、什么是JUC 二、线程和进程 1、概述  2、并发、并行 3、线程有几个状态  4、wait/sleep 区别 三、Lock锁(重点)  四、生产者和消费者问题 五、八锁现象 六、集合类不安全  七、Callable ( 简单 ) 八、常用的辅助类(必会) 1、CountDown

    2024年02月09日
    浏览(24)
  • JUC并发编程(二)

    JUC并发编程(续) 接上一篇笔记:https://blog.csdn.net/weixin_44780078/article/details/130694996 五、Java内存模型 JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU 指令优化等。 JMM 体现在以下几个方面: 原子性:保证指令不会受到线程

    2024年02月05日
    浏览(80)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包