Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >基于CAS思想的java并发AtomicBoolean实例详解

基于CAS思想的java并发AtomicBoolean实例详解

作者头像
青山师
发布于 2023-05-04 13:35:43
发布于 2023-05-04 13:35:43
31000
代码可运行
举报
运行总次数:0
代码可运行

java.util.concurrent.atomic

该包是JDK1.5开始提供的,它提供了类的小工具,支持在单个变量上解除锁的线程安全编程。此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类,其形式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  boolean compareAndSet(expectedValue, updateValue);

CAS思想

我们看到了上面提到的一个在java并发中非常重要的一类算法 – CAS: Compare And Set 比较并设置; 什么意思呢,我们以 boolean compareAndSet(expectedValue, updateValue); 方法为例来解释CAS的思想, 内存中可见的值如果和期望值(expectedValue)一致, 则将内存中的值修改为新值(updateValue),并且返回true; 否则返回false;注意 : 该操作是原子性的,意思是线程安全的。 当多个线程同时访问某个对象时,如果其中一个线程通过CAS操作获得了访问权限,则其他线程只能在该线程处理完之后才能访问。 这类似于同步字 synchronized 但是效率更高因为并没有锁的机制,即使在JDK7 之后对其进行过优化。

AtomicBoolean实例详解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 
 */
package byron4j.dlzd.curr.atomic;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;


public class AtomicDemo {

    private static volatile AtomicBoolean canExecutingFlag = new AtomicBoolean(true);



    /**
     * 
     *  业务逻辑处理:
     *  <ol>
     *    <li>Step 1</li>
     *    <li>Step 2</li>
     *  </ol>
     */
    public void executeBusiLogic(){
        if( canExecutingFlag.compareAndSet(true, false) ){
            try{
                System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑开始...");
                Thread.sleep(5000);
                System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑完毕.");
            }catch(Exception e){
                System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑失败!!!");
            }finally{
                canExecutingFlag.set(true);
            }
        }else{
            System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--已经存在处理中的业务,请稍后再试!");
        }
    }



    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(10);

        AtomicDemo demo = new AtomicDemo();

        for(int i = 0; i < 10; i++){
            es.execute(new Runnable() {

                @Override
                public void run() {
                    demo.executeBusiLogic();
                }
            });
        }

        es.shutdown();
    }

}

运行结果如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2017-09-13 22:13:45.081--pool-1-thread-3--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.082--pool-1-thread-2--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.082--pool-1-thread-6--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.081--pool-1-thread-1--处理业务逻辑开始...
2017-09-13 22:13:45.081--pool-1-thread-10--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.081--pool-1-thread-9--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.082--pool-1-thread-4--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.081--pool-1-thread-7--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.082--pool-1-thread-5--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:45.083--pool-1-thread-8--已经存在处理中的业务,请稍后再试!
2017-09-13 22:13:50.082--pool-1-thread-1--处理业务逻辑完毕.

我们看到thread-1首先获得操作权限canExecutingFlag 值为true,CAS验证通过并且将canExecutingFlag 值置为false,所以其他线程均未获得进入资格,因为处理业务逻辑花了5秒钟,其他线程得到了”已经在处理中”的提示。 为了模拟耗时操作,我们在 executeBusiLogic 方法中通过sleep使执行线程睡眠。

在实际生产中,我们可以使用该方式来处理并发问题, 比如金融领域,请求支付单做资金放款时,为了避免在同一时间请求多次,就可以使用 CAS 来控制。

CAS的缺陷–CAS的ABA问题

问题描述:

因为CAS是基于内存共享机制实现的,比如在AtomicBoolean类中使用了关键字 volatile 修饰的属性: private volatile int value;

线程t1在共享变量中读到值为A 线程t1被抢占了,线程t2执行 线程t2把共享变量里的值从A改成了B,再改回到A,此时被线程t1抢占。 线程t1回来看到共享变量里的值没有被改变,于是继续执行。 虽然线程t1以为变量值没有改变,继续执行了,但是这个过程中(即A的值被t2改变期间)会引发一些潜在的问题。ABA问题最容易发生在lock free 的算法中的,CAS首当其冲,因为CAS判断的是指针的地址。如果这个地址被重用了呢,问题就很大了。(地址被重用是很经常发生的,一个内存分配后释放了,再分配,很有可能还是原来的地址)

举一个例子:

我们进机场过安检的时候,有一个人和你的背包是一样的(瑞士牌),安检完后他把你的背包拿走了,你看下包一样的于是很淡定地登记去了,但是你的Mac Pro不见了。。

这就是ABA的问题。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-09-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解
一、JMM(java memory model)内存模型 从网上淘来二张图: 上面这张图说的是,在多核CPU的系统中,每个核CPU自带高速缓存,然后计算机主板上也有一块内存-称为主内(即:内存条)。工
菩提树下的杨过
2018/01/18
5870
java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解
3.原子变量 CAS算法
在上一篇中我们讲述了关于多线程并发,导致共享属性在内存不可见的问题。以及使用 volatile 关键字设置共享属性,使其在多线程并发中内存可见。
Devops海洋的渔夫
2022/03/23
4470
3.原子变量 CAS算法
JAVA并发编程系列(3)JUC包之CAS原理
首先,Atomic包,原子操作类,提供了用法简单、性能高效、最重要是线程安全的更新一个变量。支持整型、长整型、布尔、double、数组、以及对象的属性原子修改,支持种类非常丰富。
拉丁解牛说技术
2024/09/06
1451
aqs底层【java并发编程】
luck锁底层 aqs+cas+lucksuuport luck public void lock() { sync.lock(); } public void unlock() { sync.release(1); } Sync extends AbstractQueuedSynchronizer 手写 luck锁(aqs+cas+lucksuuport) public class GTFlock { /** * 0
高大北
2022/06/15
2650
2.JUC线程高级-原子变量与CAS算法
执行完i++后为什么结果是10,原因是因为i++操作,jvm底层实际是分为以下三步:(读-改-写)
用户1212940
2022/04/13
2130
2.JUC线程高级-原子变量与CAS算法
探索JAVA并发 - 悲观锁和乐观锁
悲观锁认为一定会有人和它同时访问目标资源,因此必须先将其锁定,常见的synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
acupt
2019/08/26
6040
并发原子技术之CAS机制
1. CAS机制 CAS定义 CAS全称为Compare-and-swap,是属于并发多线程中实现同步原子操作的指令,是依赖于硬件层次的原语发起的原子操作 从程序代码理解上,CAS包含check then act的两个动作,这两个动作在在硬件的处理器上是具备原子性,也就是在操作系统底层上已经实现对CAS算法的原子性保证 CAS 使用条件 需要输入两个数值,一个是期望修改前的值(旧值),一个是需要被设置的新值(新值) 进行CAS操作需要进行对预期值的check操作 CAS之简易版本 通过CAS设置新值 //
小坤探游架构笔记
2020/03/10
4490
并发原子技术之CAS机制
Java并发编程之CAS
在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大手段。其中 Lock 是 JDK 层面的锁机制,是轻量级锁,底层使用大量的自旋+CAS操作实现的。
编程大道
2020/08/27
4300
Java Review - 并发编程_ 信号量Semaphore原理&源码剖析
Semaphore信号量也是Java中的一个同步器,与CountDownLatch和CycleBarrier不同的是,它内部的计数器是递增的,并且在一开始初始化Semaphore时可以指定一个初始值,但是并不需要知道需要同步的线程个数,而是在需要同步的地方调用acquire方法时指定需要同步的线程个数。
小小工匠
2021/12/30
3660
Java Review - 并发编程_ 信号量Semaphore原理&源码剖析
Java并发——CAS(十)
在大多数处理器的指令中,都会实现 CAS 相关的指令,这一条指令就可以完成“比较并交换”的操作,也正是由于这是一条(而不是多条)CPU 指令,所以 CAS 相关的指令是具备原子性的,这个组合操作在执行期间不会被打断,这样就能保证并发安全。由于这个原子性是由 CPU 保证的,所以无需我们程序员来操心。
翰墨飘香
2024/05/21
2600
Java 编程问题:十一、并发-深入探索
本章包括涉及 Java 并发的 13 个问题,涉及 Fork/Join 框架、CompletableFuture、ReentrantLock、ReentrantReadWriteLock、StampedLock、原子变量、任务取消、可中断方法、线程局部、死锁等方面。对于任何开发人员来说,并发性都是必需的主题之一,在工作面试中不能被忽视。这就是为什么这一章和最后一章如此重要。读完本章,您将对并发性有相当的了解,这是每个 Java 开发人员都需要的。
ApacheCN_飞龙
2022/07/11
1.1K0
Java 编程问题:十一、并发-深入探索
JUC系列(九) CAS 与锁的理解
CAS:比较当前工作内存中的值,如果这个值是期望的,那么执行操作,如果不是就一直循环
冷环渊
2022/12/03
2910
JUC系列(九) CAS 与锁的理解
java高并发系列 - 第21天:java中的CAS,你需要知道的东西
需求:我们开发了一个网站,需要对访问量进行统计,用户每次发一次请求,访问量+1,如何实现呢?
路人甲Java
2019/12/10
5010
彻底理解Java并发:Java并发原子类
在 Jdk1.5 开始 Java 开始引进提供了 java.util.concurrent.atomic 包,到 Jdk8 时,atomic 包共提供了 16 个原子类,分为 6 种类型,分别是:①、基本类型原子类;②、数组类型原子类;③、引用类型原子类;④、原子更新属性;⑤、Adder 加法器;⑥、积累器。
栗筝i
2022/12/01
6210
AtomicStampedReference解决CAS的ABA问题
AtomicStampReference 解决CAS的ABA问题 什么是ABA ABA问题:指CAS操作的时候,线程将某个变量值由A修改为B,但是又改回了A,其他线程发现A并未改变,于是CAS将进行值交换操作,实际上该值已经被改变过,这与CAS的核心思想是不符合的 ABA解决方案 每次变量更新的时候,把变量的版本号进行更新,如果某变量被某个线程修改过,那么版本号一定会递增更新,从而解决ABA问题 AtomicReference 演示ABA问题 package com.keytech.task; impo
开源日记
2021/01/11
4120
Java 之 JUC
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待;
张小驰出没
2021/04/15
3120
Java 之 JUC
CAS,你看不懂的,我教你
用在并发,是一种思想,一种算法,也是cpu的指令,cpmpare and swap
Joseph_青椒
2023/08/26
2190
CAS,你看不懂的,我教你
JUC 多线程 CAS 算法
解释:一个线程在使用atomicInteger原子变量进行修改值的操作中,底层的CAS算法会拿自己工作空间的值去和主内存空间的值去比较,如果主内存值和期望数值5相同,则去修改为2019,否则修改失败。即CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false。
万能青年
2019/08/30
4230
多线程之原子变量CAS算法(二)
上篇博文,我们介绍了多线程之内存可见性Volatile(一),但是也遗留了一个问题,如何保证变量的"原子性操作(Atomic operations)"?
程序猿小亮
2021/01/29
3180
并发编程- java.util.concurrent用户指南
本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.jenkov.com/java-util-concurrent/index.html。 本指南已做成中英文对照阅读版的 pdf 文档,有兴趣的朋友可以去 Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf[带书签] 进行下载。
高广超
2018/12/12
1K0
相关推荐
java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验