- 浏览: 132079 次
- 性别:
- 来自: ...
文章分类
最新评论
之前看到一个帖子是关于atomic使用的,当时没有仔细分析问题,理解有误,作者回信给我,我又去看了一下.原来的问题大致如下:
这样的写法能保证同步吗?按照这个写法的话,if块一定要使用同步锁保证同步的.但是那样的话Atomic的优势将大打折扣,代码的主要问题不在if而在if内的那句赋值:longValue = new AtomicLong(0).
重新new出Atomic实例+同步锁的双重成本,可能会使代码执行的性能不尽如人意.所以我昨天想了一下,要保证同步又不使用锁其实利用Atomic的CAS应该是能做到的.写了一个小例子:
这里我把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,我想还是有必要记录一下的.在此感谢作者的回复.
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,我想还是有必要记录一下的.在此感谢作者的回复.
发表评论
文章已被作者锁定,不允许评论。
-
一道位操作的趣味编程题
2010-03-14 10:50 2124看到一道很有意思的编程题:大厅里有64盏灯,每盏灯都编 ... -
一道字符串截取的编程题
2010-03-11 10:52 2321最近接触到一道字符串截取的编程题:编写一个截取字符串的 ... -
一道多线程趣味热身题
2010-02-28 18:01 1960保持对知识点或者技术的熟悉度对于程序员至关重要,要学会 ... -
疑似Google多线程面试题的Java实现
2010-02-24 17:39 4965来到一个完全陌生的地方,即将一切从新开始,内心兴奋又忐 ... -
Mina的线程池实现分析(2)
2010-02-10 17:31 4590分析了I/O事件的存储,下面看看多个Worker同时工 ... -
Mina的线程池实现分析(1)
2010-02-10 17:28 11633线程池是并发应用中,为了减少每个任务调用的开销增强性能 ... -
多线程基础总结十一--ConcurrentLinkedQueue
2010-02-03 17:52 12952ConcurrentLinkedQueue充分使用了a ... -
LinkedBlockingQueue应用--生产消费模型简单实现
2010-01-29 20:45 8213之前介绍时LinkedBlockingQueue提到了 ... -
多线程基础总结十--LinkedBlockingQueue
2010-01-28 14:33 15443随着多线程基础总结的增多,却明显的感觉知道的越来越少, ... -
号称放倒一片的一道J2SE基础题的个人理解
2010-01-23 14:07 2847近日无意中看到一道Java基础题,号称在接受测试的10 ... -
多线程基础总结九--Mina窥探(1)
2010-01-21 23:46 5455一直以来的多线程的基础总结都是脱离应用的,但是要说多线 ... -
多线程基础总结八--ReentrantReadWriteLock
2010-01-15 23:22 7559说到ReentrantReadWriteLock,首先 ... -
多线程基础总结七--ReentrantLock
2010-01-09 23:17 7731之前总结了部分无锁机制的多线程基础,理想的状态当然是利 ... -
多线程基础总结六--synchronized(2)
2009-12-18 18:45 1912早在总结一时,我就尽量的把synchronized的重点 ... -
多线程基础总结五--atomic
2009-12-17 19:46 3594在简单介绍java.util.c ... -
多线程基础总结四--ThreadLocal
2009-12-16 19:48 2763说到ThreadLocal,首先 ... -
多线程基础总结三--volatile
2009-12-15 20:09 2583前面的两篇总结简 ... -
多线程基础总结二--Thread
2009-12-12 23:27 2711对于Thread来说 ... -
多线程基础总结一--synchronized(1)
2009-12-12 23:23 3118最近写关于并发的小应 ... -
由destory-method引发的IOC容器设计的思考
2009-12-07 16:51 1724第一次读Spring的源 ...
相关推荐
描述中的“Atomic bitops based version of ext2 atomic bitops”进一步确认了这一点,它提到这是一个基于原子位操作的ext2文件系统的版本,意味着它可能涉及到了如何在不使用锁的情况下修改位,这对于在高并发环境...
传统的连续介质力学模型将纳米结构视为体材料加上表面,但这种方法存在局限性,因为它无法提取关于表面性质的材料参数。分子动力学(MD)模拟虽然能够研究纳米线材的弹性行为,但需要考虑的变量多且复杂。因此,本文...
该原理认为,波前的每一点都可视为新波源,发出次级波,而波动的传播方向是由这些次级波的包络确定的。 文章首先从惠更斯原理计算一片树叶的影子入手,这个过程是这样的:如果光波在经过树叶时被阻挡,光波将无法...
- **问题**: 如果在对象创建完成之前就将其引用发布出去,可能会导致其他线程看到尚未完全初始化的对象。 - **解决方法**: 在构造期间使用回调接口或避免在构造函数中启动新线程。 7. **Final Fields**: - **...
Synchronized 的优点是易于使用和理解,编译器通常会对其进行优化,可以提高性能。然而,Synchronized 也有一些缺点,如它不能被Interrupt,且在资源竞争激烈的情况下性能会下降。 二、ReentrantLock ...
理解这一点对于避免变量冲突和正确使用闭包至关重要。 7. **java实现高性能的数据同步** 在多线程环境中,数据同步是保证数据一致性的重要手段。Java提供了多种同步机制,如synchronized关键字、Lock接口、信号量...
理解JMM对于理解多线程中的可见性和有序性问题至关重要。它规定了线程如何访问和修改共享变量,以及如何保证内存一致性。 十、实战面试题 面试中可能遇到的问题包括但不限于:生产者消费者模型、线程池的参数设置、...
语义化命名能够使其他开发者更快地理解代码的意图,尤其是在团队协作的项目中,这一点尤为重要。例如,如果有一个CSS样式用于处理导航栏,使用“navbar”而不是“nav_b”这样的缩写,可以使代码更易读。 在CSS5...
"互斥"则是一种更严格的同步方式,它确保同一时刻只有一个线程能访问特定的资源,实现这一点的常见工具就是信号量(sempahore)。 信号量是一种在多线程编程中用于同步的机制,由P(down)和V(up)操作组成。在ARM...
理解这一点是掌握并发编程的基础。 2. C++线程库():C++11引入了标准线程库,书中详细介绍了如何创建、管理和同步线程,包括std::thread类的使用,以及线程安全性的考量。 3. 同步原语:书中深入讨论了各种同步...
线程安全的类如Atomic系列类和Collections.synchronizedXXX()方法可以帮助我们实现这一点。 9. **线程性能调优**:优化多线程程序涉及许多方面,包括合理设置线程数量、避免过度同步、减少上下文切换、使用适当的...
"BOOM计数器 v1.0" 是一个专门设计用于图像和文字双模式显示...通过深入理解其内部机制,开发者可以学习到计数器类的设计原则、并发控制策略以及用户界面的构建方法,对于提升编程技能和理解应用程序设计有很好的帮助。
为了更好地理解和应用ZooKeeper,你可以阅读《zookeeper电子参考书》,这本书详细介绍了ZooKeeper的原理、设计、使用方法以及常见问题的解决方案。通过学习,你不仅可以掌握分布式一致性理论,还能具备实际操作和...
首先,我们需要理解“画布”在这个上下文中的含义。它通常指的是一个可视化的编辑环境,用户可以通过拖放元素来构建网页布局,就像在画布上绘制一样。这种工具大大简化了非程序员创建自定义网站的过程。 “改版”的...
要实现这一点,通常有两种方法:一是通过信道(channel)来进行数据传递;二是利用`sync`和`sync/atomic`包提供的同步原语来保护共享数据。 #### 三、事件的发生次序 在Go中,事件的发生次序是指内存操作执行的一种...
4. **内存区域共享**:使用`kmalloc`分配内存,并通过原子操作(如`atomic_t`)确保多线程环境下数据的一致性。 5. **内核消息传递机制**:例如,使用`kobject`、`kmsg_distributor`等机制,实现模块间的异步通信。...
7. **死锁、活锁和饥饿**: 这是并发编程中的常见问题,理解并避免这些情况是至关重要的。死锁发生在两个或更多线程相互等待对方释放资源时;活锁是线程不断尝试获取资源但无法成功,导致系统停滞不前;而饥饿则是一...
原子操作(Atomic Operation)是CUDA编程中的关键特性,它确保了在多线程环境下的数据一致性。当多个线程尝试同时修改同一内存位置时,原子操作可以确保这些操作的顺序和结果是正确的。FastAtomicAdd是CUDA提供的一...
Java提供了多种机制来保证这一点,如`synchronized`关键字、`volatile`关键字、`Atomic`类以及`Lock`接口。在断点续传中,可能使用这些机制来管理共享的文件下载状态和进度。 3. **HTTP协议**:HTTP(超文本传输...
TileLink的Broadcast模式可以实现这一点,例如在初始化全局变量或更新所有处理器的时钟速率时。 7. RISC-V与TileLink的集成: RISC-V架构的模块化特性使其能够轻松地与TileLink接口配合。处理器核可以通过TileLink...