【并发知识点】CAS的实现原理及应用

news2024/9/22 21:31:16

系列文章目录

AQS的实现原理及应用
CAS的实现原理及应用

在这里插入图片描述


文章目录

  • 系列文章目录
  • 前言
  • 1、CAS的概念
  • 2、CAS的实现原理
  • 3、单JVM内锁CAS实现
    • 3.1、效果
  • 4、模拟赛龙舟比赛


前言

本章节介绍CAS概念、实现原理,并通过java代码应用,最终模拟赛龙舟比赛。

1、CAS的概念

CAS的全称为:CompareAndSwap,直译为对比和交换。
CAS实际是普遍处理器都支持的一条指令,这条指令通过判断当前内存值V、旧的预期值A、即将更新的值B是否相等来对比并设置新值,从而实现变量的原子性。
Synchronized会线程阻塞称为悲观锁,CAS不会使线程阻塞称为乐观锁。悲观锁其他没有获取锁的线程是不会执行代码的,而乐观锁是可以使多个线程同时访问代码,可是会判断是否有更新决定是否重新执行。

2、CAS的实现原理

CAS的原理:通过三个参数,当前内存的变量值V、旧的预期值A、即将更新的值B。通过判断是V和A是否相等查看当前变量值是否被其他线程改变,如果相等则变量没有被其他线程更改,就把B值赋予V;如果不相等则做自旋操作。
举例:假设i的初始值为0,现两线程分别执行i++操作,看看CAS会如何执行:

1线程:A = 0,B = 1
2线程:A = 0,B = 1

此时两个线程的旧的期望值A、更新的B值都是一样的
假设1线程先执行,线程1从内存中拿到i的值V,此时V等于0,刚好和旧的期望值A相等,就把更新的值B赋值到内存i值V中。
2线程执行时,此时拿到内存的V值为1,和旧的预期值0不想等,则不做更新B的赋值操作,通过自旋把旧的预期值A=V,并再次确定CAS指令。
在这里插入图片描述

JDK提供的原子操作类就是基于CAS来实现原子性,比如:AtomicInteger、AtomicIntegerArray、AtomicDouble、AtomicBoolean等

3、单JVM内锁CAS实现

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/***
 * @title AtomicExample
 * @desctption CAS
 * @author Kelvin
 * @create 2023/6/14 17:08
 **/
public class AtomicExample {
    private static Map<String, Boolean> map = new HashMap<>();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //未加锁
        map.put("lock", true);
        for (int i = 0; i < 20; i++) {
            int finalI = i;
            executorService.submit(
                    () -> {
                        boolean isRotate = true;
                        while (isRotate) {
                            boolean vLock = map.get("lock");
                            if( vLock ) {
                                boolean aLock = map.get("lock");
                                if( vLock == aLock ) {
                                    //执行业务逻辑
                                    //加锁
                                    map.put("lock", false);
                                    System.out.println( "执行业务逻辑, i: " + finalI);
                                    try {
                                        Thread.sleep(2000);
                                    } catch (InterruptedException e) {
                                        throw new RuntimeException(e);
                                    }
                                    isRotate = false;
                                    //释放锁
                                    map.put("lock", true);
                                } else {
                                    System.out.println("自旋,重新获取锁!");
                                    continue;
                                }
                            }
                        }
                    }
            );
        }

        Thread.sleep(20 * 1000);
        System.out.println("end");
        executorService.shutdown();
        
    }
}

3.1、效果

执行业务逻辑, i: 1
执行业务逻辑, i: 5
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 4
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 10
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 9
执行业务逻辑, i: 2
自旋,重新获取锁!
执行业务逻辑, i: 3
自旋,重新获取锁!
执行业务逻辑, i: 0
执行业务逻辑, i: 12
执行业务逻辑, i: 11
执行业务逻辑, i: 8
执行业务逻辑, i: 6
执行业务逻辑, i: 7
执行业务逻辑, i: 14
自旋,重新获取锁!
执行业务逻辑, i: 15
执行业务逻辑, i: 16
执行业务逻辑, i: 18
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 17
执行业务逻辑, i: 19
执行业务逻辑, i: 13
end

4、模拟赛龙舟比赛

在这个程序中,我们将使用Java的AtomicInteger来实现一个裁判的计时器,模拟一个赛龙舟比赛中多支队伍竞争的场景。每个队伍都会在启动时创建一个独立的线程,并在程序中使用LockFreeQueue来模拟龙舟的运动。同时,程序中还会使用CountDownLatch来控制所有龙舟同时开始比赛,并使用CyclicBarrier来模拟所有队伍完成比赛后的庆祝活动。

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class DragonBoatRace {
    private static final int TEAM_NUM = 4; // 参赛队伍数
    private static final int BOAT_NUM = 1; // 龙舟数量
    private static final Random random = new Random();
    private static final AtomicInteger time = new AtomicInteger(0);
    private static final CountDownLatch startLatch = new CountDownLatch(TEAM_NUM);
    private static final CyclicBarrier finishBarrier = new CyclicBarrier(TEAM_NUM + 1);
    private static final LockFreeQueue<Integer> queue = new LockFreeQueue<>();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(TEAM_NUM);
        for (int i = 0; i < TEAM_NUM; i++) {
            executorService.submit(new Team(i + 1));
        }
        startLatch.await(); // 等待所有队伍准备就绪
        System.out.println("比赛开始!");
        for (int i = 0; i < BOAT_NUM; i++) {
            new Thread(new Boat(i + 1)).start();
        }
        System.out.println("龙舟已经准备好!");
        finishBarrier.await(); // 等待所有队伍完成比赛
        System.out.println("所有队伍完成比赛,开始庆祝!");
        executorService.shutdown(); // 关闭线程池
    }

    static class Team implements Runnable {
        private final int teamId;

        public Team(int teamId) {
            this.teamId = teamId;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(1000 * teamId); // 模拟队伍准备时间
                System.out.println("队伍" + teamId + "已准备就绪!");
                startLatch.countDown(); // 准备就绪,计数器减一
                queue.add(1); // 龙舟前进一步
                while (time.get() < 2000) { // 等待龙舟到达终点
                    Thread.yield();
                }
                System.out.println("队伍" + teamId + "已完成比赛,用时" + time.get() + "ms!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                try {
                    finishBarrier.await(); // 等待其他队伍完成比赛
                    System.out.println("队伍" + teamId + "正在庆祝!");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class Boat implements Runnable {
        private final int boatId;

        public Boat(int boatId) {
            this.boatId = boatId;
        }

        @Override
        public void run() {
            while (!queue.isEmpty()) { // 龙舟前进,直到到达终点
                if (queue.poll() != null) {
                    time.addAndGet(random.nextInt(10) + 1); // 龙舟前进一步,用时1~10ms
                }
            }
            try {
                finishBarrier.await(); // 等待所有队伍完成比赛
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    static class LockFreeQueue<E> {
        private static class Node<E> {
            final E item;
            volatile Node<E> next;

            Node(E item) {
                this.item = item;
            }
        }

        private volatile Node<E> head;
        private volatile Node<E> tail;

        public boolean isEmpty() {
            return head == null;
        }

        public void add(E item) {
            Node<E> node = new Node<>(item);
            while (true) {
                Node<E> last = tail;
                Node<E> next = last == null ? head : last.next;
                if (last == tail) {
                    if (next == null) {
                        if (compareAndSetNext(last, null, node)) {
                            compareAndSetTail(last, node);
                            return;
                        }
                    } else {
                        compareAndSetTail(last, next);
                    }
                }
            }
        }

        public E poll() {
            while (true) {
                Node<E> first = head;
                Node<E> last = tail;
                Node<E> next = first == null ? null : first.next;
                if (first == head) {
                    if (first == last) {
                        if (next == null) {
                            return null;
                        }
                        compareAndSetTail(last, next);
                    } else {
                        E item = next.item;
                        if (compareAndSetHead(first, next)) {
                            return item;
                        }
                    }
                }
            }
        }

        private boolean compareAndSetHead(Node<E> expect, Node<E> update) {
            return unsafe.compareAndSwapObject(this, headOffset, expect, update);
        }

        private boolean compareAndSetTail(Node<E> expect, Node<E> update) {
            return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
        }

        private boolean compareAndSetNext(Node<E> node, Node<E> expect, Node<E> update) {
            return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
        }

        private static final sun.misc.Unsafe unsafe;
        private static final long headOffset;
        private static final long tailOffset;
        private static final long nextOffset;

        static {
            try {
                unsafe = getUnsafe();
                Class<?> k = LockFreeQueue.class;
                headOffset = unsafe.objectFieldOffset(k.getDeclaredField("head"));
                tailOffset = unsafe.objectFieldOffset(k.getDeclaredField("tail"));
                nextOffset = unsafe.objectFieldOffset(Node.class.getDeclaredField("next"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }

        private static sun.misc.Unsafe getUnsafe() throws Exception {
            Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (sun.misc.Unsafe) field.get(null);
        }
    }
}

在这个程序中,我们模拟了4个队伍参加赛龙舟比赛。每个队伍都在启动时创建一个独立的线程,并在比赛前等待1-4s的准备时间。当所有队伍都准备就绪后,裁判发出比赛开始信号,龙舟开始前进。程序中使用LockFreeQueue来模拟龙舟的运动,每次龙舟前进一步,用时1~10ms。当某个队伍完成比赛后,程序会使用CyclicBarrier来等待其他队伍完成比赛,并且进行庆祝活动。

总之,基于CAS的Java多线程程序可以很好地模拟赛龙舟比赛中的多支队伍竞争的场景。通过使用Java的AtomicInteger和LockFreeQueue等基于CAS的同步机制,我们可以实现高效的线程协作和同步操作。

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

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

相关文章

设计模式之适配器模式笔记

设计模式之适配器模式笔记 说明Adapter(适配器)目录类适配器模式示例类图适配者类的接口适配者类目标接口具体的SD卡类计算机类适配器类测试类 对象适配器模式适配者类的接口适配者类目标接口具体的SD卡类计算机类适配器类测试类 说明 记录下学习设计模式-适配器模式的写法。J…

力扣高频SQL50题(基础版)——第十天

力扣高频SQL50题(基础版)——第十天 1 只出现过一次的最大数字 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出1 1.1.3 示例输入输出2 1.2 示例sql语句 # 查不到时的结果自然就为Null SELECT MAX(t.num) num FROM (SELECT numFROM MyNumbersGROUP By numHAVING count…

窥探系列之Mybatis-plus BaseMapper实现

我们知道&#xff0c;mybatisplus的BaseMapper接口中提供了一些如updateById的方法&#xff0c;框架本身已经实现了这些CRUD功能&#xff0c;基本的CRUD我们就没必要写sql&#xff0c;直接使用java语法就能对数据进行操控&#xff0c;很方便。那么这些功能是如何被实现的呢&…

【并发知识点】AQS的实现原理及应用

系列文章目录 AQS的实现原理及应用 CAS的实现原理及应用 文章目录 系列文章目录前言一、AQS是什么&#xff1f;1、应用场景2、优缺点 二、案例应用1.使用AQS来实现一个简单的互斥锁2.模拟赛龙舟程序 总结 前言 在Java技术方面&#xff0c;AQS指的是AbstractQueuedSynchronize…

2023最新高薪岗位大爆料,大模型算法工程师!凭什么人均月薪50K

大模型算法工程师工资收入一般多少钱一个月&#xff1f; 最多人拿50K以上占 53.7%&#xff0c;2023年较2022年增长了10%。 按学历统计&#xff0c;本科工资&#xffe5;41.9K。 按经验&#xff0c;1-3年工资&#xffe5;40.0K。 一起来看华为招聘的大模型工程师的工资水准 岗位…

[补充]机器学习实战|第二周|第2章:监督学习|课后习题

目录 第二章 监督学习 2. 使用不同的超参数&#xff0c;如kernel"linear"和kernel“rbf”&#xff0c;尝试一个支持向量机回归器。并思考最好的SVR预测器是如何工作的&#xff1f; [代码]3. 为MNIST数据集构建一个分类器&#xff0c;并在测试集上达成超过97%的精度…

关于Java中单例模式(饿汉模式和懒汉模式)的简析

目录 一.什么是单例模式 二.饿汉模式和懒汉模式 饿汉模式 代码 懒汉模式 代码 关于多线程安全的问题 如何解决懒汉模式多线程安全问题 双if判断 一.什么是单例模式 简单来说,就是我们在程序中通过代码进行限制,在该程序中 只能创建一个对象 二.饿汉模式和懒汉模式 …

【2023,学点儿新Java-17】变量与运算符:Java中的关键字及类型划分(附: 官网) | 保留字 | 字面量 | 附:Java部分关键字介绍

前情回顾&#xff1a; 【2023&#xff0c;学点儿新Java-16】编程语言的学习方法总结 | 编程的本质和架构 | 如何深度理解编程知识和技能 | 如何成为优秀的软件开发工程师 | 附&#xff1a;Java初学者的困惑&#xff01;【2023&#xff0c;学点儿新Java-15】案例分享&#xff1…

机器视觉初步7:模板匹配专题

今天端午&#xff0c;祝各位端午安康&#xff01; 今天来说说模板匹配这个专题。 模板匹配&#xff08;Template Matching&#xff09;是一种图像处理技术&#xff0c;用于在一幅图像上查找与另一幅模板图像相同的区域。模板图像和待匹配图像的大小相同。模板匹配的目的是在待…

【MongoDB大作业】MongoDB服务器的部署

【MongoDB大作业】MongoDB服务器的部署 作业要求作业步骤一、在VMware Workstations安装Linux操作系统&#xff08;最小安装即可&#xff09;二、安装完成后登录系统三、将ip地址设置为固定ip地址192.168.80.134四、设置虚拟网络编辑器五、使用 CRT 工具远程连接虚拟机六、下载…

《项目实战》构建SpringCloud alibaba项目(一、构建父工程、公共库、网关))

系列文章目录 构建SpringCloud alibaba项目&#xff08;一、构建父工程、公共库、网关&#xff09; 构建SpringCloud alibaba项目&#xff08;二、构建微服务鉴权子工程store-authority-service&#xff09; 文章目录 系列文章目录1、概要2、整体架构流程2.1、技术结构组成部分…

非监督学习

聚类Clustering 查看大量数据点&#xff0c;自动找到彼此相关或相似的数据点 K-means算法 原理 1.随机选择点&#xff0c;找聚类的中心位置。将点分配给簇质心 2.移动簇质心 不断重复这两个步骤 优化目标 成本函数失真函数distortion 在每次迭代中&#xff0c;失真成本…

极致呈现系列之:Echarts旭日图的绚丽奇观

目录 什么是旭日图旭日图的特性及应用场景旭日图的特性应用场景 旭日图常用的配置项创建基本的旭日图自定义旭日图样式样式旭日图的高级应用 什么是旭日图 旭日图是一种可视化图表&#xff0c;用于展示层级结构和层级之间的关系。它以一个圆形为基础&#xff0c;由多层的环形图…

【从零开始学习JAVA | 第七篇】API 简介

目录 前言 API介绍&#xff1a; 总结&#xff1a; 前言 这篇章为前导性文章&#xff0c;主要向大家介绍了什么是API&#xff0c;不要求掌握&#xff0c;感兴趣的小伙伴们可以看一看。 API介绍&#xff1a; API&#xff08;Application Programming Interface&#xff09;是指…

webpack原理之开发第一个loader

一. 搭建项目结构 整体项目结构如图&#xff1a; 1. 初始化包管理器package.json npm init -y 2. 打包入口文件src/main.js 3. 单页面入口public/index.html 4. 配置webpack.config.js const path require(path) const HtmlWebpackPlugin require("html-webpack-plu…

ChatBot聊天机器人学习1

1、Bot定义 能执行大量自动化、高速或机械式、繁琐的工作的计算机程序&#xff0c;包括但不仅限于聊天功能 2、Retrieval-based KE&#xff08;知识网络&#xff09;基于信息的提取。&#xff08;检索的过程中有延迟&#xff0c;设置比较快捷的检索方式&#xff09; 2.1 Int…

一看就懂的gulp操作指南:让前端工作变得更加轻松

文章目录 I. 简介什么是gulp为什么要使用gulp安装gulp II. Gulp入门任务&#xff08;task&#xff09;和流&#xff08;stream&#xff09;的概念使用gulp来处理文件基本的gulp任务&#xff08;拷贝文件、压缩文件、编译Sass等&#xff09; III. Gulp进阶使用插件开发面向生产的…

基于Python+tensorflow深度学习VGG-19图像风格迁移+自动去噪(MNIST数据集)机器学习+人工智能+神经网络——含全部Python工程源码

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境TensorFlow 环境 模块实现1. 图片处理2. 模型构造 系统测试工程源代码下载其它资料下载 前言 本项目基于 MNIST 数据集&#xff0c;使用 VGG-19 网络模型&#xff0c;将图像进行风格迁移&#xff0c;实现去噪功…

数字信号处理课程设计——调制与解调

文字目录 数字信号处理课程设计 摘要&#xff1a; 1绪论 1.1通信信号的调制与解调 1.2设计题目 2卷积定理和希尔伯特公式理论推导 2.1卷积定理 ​2.2希尔伯特公式 3信号DSB调制与希尔伯特解调 3.1过程框图 3.2相关理论推导 3.2.1卷积定理在调制中的应用 3.2.2希尔…

某马 qiankun 公开课 学习记录

端午早晨阳光正好&#xff0c;起来学习一小下 客观评价一哈&#xff1a;此视频适合不了解 qiankun 的朋友入门观看&#xff0c;更详细的使用方法还是推荐 qiankun 官网哦&#xff0c;老师讲的生动活泼&#xff0c;值得萌新一听 某马 qiankun 公开课 - bilibili ovo很多公司的…