`
ftj20003
  • 浏览: 132079 次
  • 性别: Icon_minigender_1
  • 来自: ...
社区版块
存档分类
最新评论

关于atomic问题的一点理解

    博客分类:
  • Java
阅读更多
    之前看到一个帖子是关于atomic使用的,当时没有仔细分析问题,理解有误,作者回信给我,我又去看了一下.原来的问题大致如下:
private AtomicLong longValue = new AtomicLong(0);
if(longValue.incrementAndGet() > 50) {
     longValue = new AtomicLong(0);
}

这样的写法能保证同步吗?按照这个写法的话,if块一定要使用同步锁保证同步的.但是那样的话Atomic的优势将大打折扣,代码的主要问题不在if而在if内的那句赋值:longValue = new AtomicLong(0).
    重新new出Atomic实例+同步锁的双重成本,可能会使代码执行的性能不尽如人意.所以我昨天想了一下,要保证同步又不使用锁其实利用Atomic的CAS应该是能做到的.写了一个小例子:
public class AtomicCounterSample {
    private final AtomicLong longValue = new AtomicLong(0);

    public void incrementOrClear() {

//      String name = Thread.currentThread().getName();

        long var = longValue.get();
        if(var >= 50) {
            longValue.compareAndSet(var,0); // 1
        }
        else {
//          System.out.println(name + ": " + var);

            longValue.compareAndSet(var,var + 1l); // 2
        }
    }

    public static void main(String[] args) {
        final AtomicCounterSample sample = new AtomicCounterSample();

        Thread threada = new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 100; i++) {
                    sample.incrementOrClear();
                }
            }
        });
        threada.setName("A");

        Thread threadb = new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 150; i++) {
                    sample.incrementOrClear();
                }
            }
        });
        threadb.setName("B");

        threada.start();
        threadb.start();
    }
}

这里我把AtomicLong的实例定义成final的,避免了实例化的开销.incrementOrClear()方法的作用就是递增或者清零.首先从理论上的保证是所有对AtomicLong的实例longValue的操作都是CAS的,所以其不会出现重复赋值的现象.这里我开了两个测试线程,循环调用incrementOrClear()方法,两个线程在方法内1,2处的情况分析如下:

    1.线程A,B都处于2处,有两个可能:(1)线程A,B的局部变量var相同,这时候有一个线程的CAS成功,另一个的var就会与longValue的最新值不同,CAS失败,保证了不重复写.(2)线程A,B的var不同,例如线程A的var=7之后A暂缓,B线程一直CAS直到其var=30时A继续执行,A,B同时进入2.这个时候线程A的CAS显然要失败,因为longValue的最新值是30,而B的CAS成功,保证了longValue的递增,同时A再次调用方法时,var的值被同步到最新的值.

    2.线程A,B都处于1处,这是只有一种可能就是两者的var都是50,此时也是只有一个线程能够成功的执行longValue的CAS操作使其清零.

    3.线程A,B分布在1,2两处.那么拥有与longValue的最新值一致的var会成功执行CAS操作.假设A在1处,B在2处.A的var=50,B的var=49.若longValue的最新值是50则清零成功.若longValue的最新值是49,这种情况是A的var=50时被暂缓了,B执行了清零并且新循环到49.这个时候依然是B的CAS成功,A的清零失败.即使此时B被暂缓了,那么A也会失败之后再次调用方法更新var的值替代B执行递增.如果恰好循环到B暂缓时的var值时B也继续执行了,那么就是分析1的情况(1).

    所以上述的分析,我认为任何情况都包括在内了,能够保证无锁机制的同步.并且实际运行也能体现了特别是3的分析:线程的,与longValue最新值不同的,var值再次打印时会被刷新而不是递增破坏longValue的唯一性.通过这个机会再次认识Atomic的CAS,我想还是有必要记录一下的.在此感谢作者的回复.
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    ext2-atomic-setbit.rar_atomic

    描述中的“Atomic bitops based version of ext2 atomic bitops”进一步确认了这一点,它提到这是一个基于原子位操作的ext2文件系统的版本,意味着它可能涉及到了如何在不使用锁的情况下修改位,这对于在高并发环境...

    Elastic property of fcc metal nanowires via an atomic-scale analysis

    传统的连续介质力学模型将纳米结构视为体材料加上表面,但这种方法存在局限性,因为它无法提取关于表面性质的材料参数。分子动力学(MD)模拟虽然能够研究纳米线材的弹性行为,但需要考虑的变量多且复杂。因此,本文...

    The Research of the Properties of Atomic Absorption Photon and Stimulated Radiation by Using Huygens' Principle

    该原理认为,波前的每一点都可视为新波源,发出次级波,而波动的传播方向是由这些次级波的包络确定的。 文章首先从惠更斯原理计算一片树叶的影子入手,这个过程是这样的:如果光波在经过树叶时被阻挡,光波将无法...

    Java 并发核心编程

    - **问题**: 如果在对象创建完成之前就将其引用发布出去,可能会导致其他线程看到尚未完全初始化的对象。 - **解决方法**: 在构造期间使用回调接口或避免在构造函数中启动新线程。 7. **Final Fields**: - **...

    Lock、Synchoronized和ReentrantLock的使用

    Synchronized 的优点是易于使用和理解,编译器通常会对其进行优化,可以提高性能。然而,Synchronized 也有一些缺点,如它不能被Interrupt,且在资源竞争激烈的情况下性能会下降。 二、ReentrantLock ...

    学习笔记

    理解这一点对于避免变量冲突和正确使用闭包至关重要。 7. **java实现高性能的数据同步** 在多线程环境中,数据同步是保证数据一致性的重要手段。Java提供了多种同步机制,如synchronized关键字、Lock接口、信号量...

    多线程面试专题及答案

    理解JMM对于理解多线程中的可见性和有序性问题至关重要。它规定了线程如何访问和修改共享变量,以及如何保证内存一致性。 十、实战面试题 面试中可能遇到的问题包括但不限于:生产者消费者模型、线程池的参数设置、...

    CSS开发工具CSS命名工具之Google在线翻译.docx

    语义化命名能够使其他开发者更快地理解代码的意图,尤其是在团队协作的项目中,这一点尤为重要。例如,如果有一个CSS样式用于处理导航栏,使用“navbar”而不是“nav_b”这样的缩写,可以使代码更易读。 在CSS5...

    驱动程序之同步阻塞互斥的源码

    "互斥"则是一种更严格的同步方式,它确保同一时刻只有一个线程能访问特定的资源,实现这一点的常见工具就是信号量(sempahore)。 信号量是一种在多线程编程中用于同步的机制,由P(down)和V(up)操作组成。在ARM...

    Cpp Concurrency In Action 中英文版

    理解这一点是掌握并发编程的基础。 2. C++线程库():C++11引入了标准线程库,书中详细介绍了如何创建、管理和同步线程,包括std::thread类的使用,以及线程安全性的考量。 3. 同步原语:书中深入讨论了各种同步...

    JAVA多线程教材

    线程安全的类如Atomic系列类和Collections.synchronizedXXX()方法可以帮助我们实现这一点。 9. **线程性能调优**:优化多线程程序涉及许多方面,包括合理设置线程数量、避免过度同步、减少上下文切换、使用适当的...

    BOOM计数器 v1.0(图片/文字双模式显示)

    "BOOM计数器 v1.0" 是一个专门设计用于图像和文字双模式显示...通过深入理解其内部机制,开发者可以学习到计数器类的设计原则、并发控制策略以及用户界面的构建方法,对于提升编程技能和理解应用程序设计有很好的帮助。

    从PAXOS到ZOOKEEPER分布式一致性原理与实践

    为了更好地理解和应用ZooKeeper,你可以阅读《zookeeper电子参考书》,这本书详细介绍了ZooKeeper的原理、设计、使用方法以及常见问题的解决方案。通过学习,你不仅可以掌握分布式一致性理论,还能具备实际操作和...

    画布(改:添加代码编辑器),免费分享,希望给你们带来一点小帮助

    首先,我们需要理解“画布”在这个上下文中的含义。它通常指的是一个可视化的编辑环境,用户可以通过拖放元素来构建网页布局,就像在画布上绘制一样。这种工具大大简化了非程序员创建自定义网站的过程。 “改版”的...

    Go 内存模型 - Go 编程语言

    要实现这一点,通常有两种方法:一是通过信道(channel)来进行数据传递;二是利用`sync`和`sync/atomic`包提供的同步原语来保护共享数据。 #### 三、事件的发生次序 在Go中,事件的发生次序是指内存操作执行的一种...

    Linux下内核模块编程技巧

    4. **内存区域共享**:使用`kmalloc`分配内存,并通过原子操作(如`atomic_t`)确保多线程环境下数据的一致性。 5. **内核消息传递机制**:例如,使用`kobject`、`kmsg_distributor`等机制,实现模块间的异步通信。...

    Java并发编程

    7. **死锁、活锁和饥饿**: 这是并发编程中的常见问题,理解并避免这些情况是至关重要的。死锁发生在两个或更多线程相互等待对方释放资源时;活锁是线程不断尝试获取资源但无法成功,导致系统停滞不前;而饥饿则是一...

    cuda-使用cuda并行加速实现之FastAtomicAdd.zip

    原子操作(Atomic Operation)是CUDA编程中的关键特性,它确保了在多线程环境下的数据一致性。当多个线程尝试同时修改同一内存位置时,原子操作可以确保这些操作的顺序和结果是正确的。FastAtomicAdd是CUDA提供的一...

    Java代码实例-多线程与线程安全实践-基于Http协议的断点续传.rar

    Java提供了多种机制来保证这一点,如`synchronized`关键字、`volatile`关键字、`Atomic`类以及`Lock`接口。在断点续传中,可能使用这些机制来管理共享的文件下载状态和进度。 3. **HTTP协议**:HTTP(超文本传输...

    tlelink 1.7手册

    TileLink的Broadcast模式可以实现这一点,例如在初始化全局变量或更新所有处理器的时钟速率时。 7. RISC-V与TileLink的集成: RISC-V架构的模块化特性使其能够轻松地与TileLink接口配合。处理器核可以通过TileLink...

Global site tag (gtag.js) - Google Analytics