接触到AtomicLong的原因是在看guava的LoadingCache相关代码时,关于LoadingCache,其实思路也非常简单清晰:用模板模式解决了缓存不命中时获取数据的逻辑,这个思路我早前也正好在项目中使用到。
final void retryUpdate( long x, HashCode hc, boolean wasUncontended) { int h = hc.code; boolean collide = false ; // True if last slot nonempty for (;;) { Cell[] as; Cell a; int n; long v; if ((as = cells) != null && (n = as.length) > 0 ) { // 分支1 if ((a = as[(n - 1 ) & h]) == null ) { if (busy == 0 ) { // Try to attach new Cell Cell r = new Cell(x); // Optimistically create if (busy == 0 && casBusy()) { boolean created = false ; try { // Recheck under lock Cell[] rs; int m, j; if ((rs = cells) != null && (m = rs.length) > 0 && rs[j = (m - 1 ) & h] == null ) { rs[j] = r; created = true ; } } finally { busy = 0 ; } if (created) break ; continue ; // Slot is now non-empty } } collide = false ; } else if (!wasUncontended) // CAS already known to fail wasUncontended = true ; // Continue after rehash else if (a.cas(v = a.value, fn(v, x))) break ; else if (n >= NCPU || cells != as) collide = false ; // At max size or stale else if (!collide) collide = true ; else if (busy == 0 && casBusy()) { try { if (cells == as) { // Expand table unless stale Cell[] rs = new Cell[n << 1 ]; for ( int i = 0 ; i < n; ++i) rs[i] = as[i]; cells = rs; } } finally { busy = 0 ; } collide = false ; continue ; // Retry with expanded table } h ^= h << 13 ; // Rehash h ^= h >>> 17; h ^= h << 5 ; } else if (busy == 0 && cells == as && casBusy()) { //分支2 boolean init = false ; try { // Initialize table if (cells == as) { Cell[] rs = new Cell[ 2 ]; rs[h & 1 ] = new Cell(x); cells = rs; init = true ; } } finally { busy = 0 ; } if (init) break ; } else if (casBase(v = base, fn(v, x))) break ; // Fall back on using base } hc.code = h; // Record index for next time } |
可以看到,LongAdder确实用了很多心思减少并发量,并且,每一步都是在”没有更好的办法“的时候才会选择更大开销的操作,从而尽可能的用最最简单的办法去完成操作。追求简单,但是绝对不粗暴。
————————————————分割线——————————————————————-
昨天在coolshell 投稿后 (文章在这里) 和左耳朵耗子简单讨论了下,发现左耳朵耗子对读者思维的引导还是非常不错的,在第一次发现这个类后,对里面的实现又提出了更多的问题,引导大家思考,值得学习,赞一个~
我们 发现的问题有这么几个:
1. jdk 1.7中是不是有这个类?
我确认后,结果如下: jdk-7u51版本上 上还没有 但是jdk-8u20 版本上已经有了。代码基本一样 ,增加了对double类型的支持和删除了一些冗余的代码。
2. base有没有参与汇总?
base在调用intValue等方法的时候是会汇总的:
3. base的顺序可不可以调换?
左耳朵耗子,提出了这么一个问题: 在add方法中,如果cells不会为空后,casBase方法一直都没有用了?
因此,我想可不可以调换add方法中的判断顺序,比如,先做casBase的判断,结果是 不调换可能更好,调换后每次都要CAS一下,在高并发时,失败几率非常高,并且是恶性循环,比起一次判断,后者的开销明显小很多,还没有副作用。因此,不调换可能会更好。
4. AtomicLong可不可以废掉?
我的想法是可以废掉了,因为,虽然LongAdder在空间上占用略大,但是,它的性能已经足以说明一切了,无论是从节约空的角度还是执行效率上,AtomicLong基本没有优势了,具体看这个测试(感谢coolshell读者Lemon的回复):http://blog.palominolabs.com/2014/02/10/java-8-performance-improvements-longadder-vs-atomiclong/
原文地址: http://coolshell.cn/articles/11454.html
相关推荐
Disruptor通过Sequence、Sequencer和Sequence Barrier实现无锁操作,确保在高并发下仍能保持低延迟。 #### (3) 依赖关系管理 Disruptor使用Sequence Barrier来管理消费者和生产者间的依赖,以及消费者间的依赖。它...
LongAdder的实现原理图可以分为三个部分:Cells数组、基值变量base和sum()方法。Cells数组用于存储多个线程的操作结果,基值变量base用于存储初始值,sum()方法用于将所有Cell数组中的value和base累加作为返回值。 ...
在实际应用中,LongAdder可以用来实现各种原子性操作,例如计数器、分布式锁、统计数据等等。 LongAdder的使用非常简单,只需要创建一个LongAdder对象,然后使用其提供的方法来进行原子性操作。 例如,使用...
Atomic类提供了一种无锁的方式来实现线程安全的操作。Atomic类使用CAS(Compare-And-Swap)操作来实现原子操作。CAS操作是一种原子操作,用于比较并交换变量的值。 为什么使用Atomic类? 使用Atomic类可以避免使用...
- **LongAdder**: 性能最佳,这得益于其高效的分段累加机制。 #### 四、结论 通过上述分析和实验结果可以看出,在多线程环境下进行自增操作时,应优先考虑使用`LongAdder`。对于需要更高灵活性的场景,则可以选择`...
通过对代码的流程分析,一步一步拆解,将源码解读变得简单
计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料计算机技术、IT咨询、人工智能AI理论介绍,学习...
通过使用LongAdder等无锁算法,Disruptor避免了传统锁机制带来的性能瓶颈。此外,它采用Sequence机制,确保了生产者与消费者之间的顺序一致性,避免了数据竞争。 2. **环形缓冲区的工作流程** 生产者通过一个叫做...
6. **LongAdder**:对于计数器操作,`LongAdder`是一种更高效的替代方案,尤其是在JDK 8及更高版本中。 通过上述总结,《阿里巴巴Java工作手册》不仅提供了实用的编程指南,还分享了许多高级技巧,对于希望提升自己...
LongAdder的实现原理是通过CAS乐观锁保证原子性,通过自旋保证当次修改的最终修改成功。在竞争不激烈的时候,所有线程都是通过CAS对同一个变量(Base)进行修改,当竞争激烈的时候,会将根据当前线程哈希到对于Cell...
8. **并发改进**:包括Fork/Join框架的优化,更高效的并发数据结构,如LongAdder和DoubleAdder,以及改进的并发工具类。 9. **String和StringBuilder优化**:新增了一些方法,如`join()`和`repeat()`,使得字符串...
2. 缓存:Guava提供了一个高效的本地缓存实现,使得我们可以快速地存储和检索数据。开发者可以自定义缓存的大小、过期策略,以及在缓存项被移除时的回调函数,从而在内存管理上具有更大的灵活性。 3. 原语支持:...
9. **新的反射API**:JDK 1.8对反射API也做了改进,如`MethodHandle`和`MethodType`,提供了更高效且类型安全的反射机制。 10. **枚举的常量工厂方法**:枚举类可以定义静态工厂方法来创建其实例,增强了枚举的灵活...
8. **新的数值类型`LongAdder`和`DoubleAdder`**:这些类提供了线程安全的计数器,相比于`synchronized`修饰的`AtomicLong`,它们在高并发环境下性能更优。 9. **并行流(Parallel Streams)**:Stream API支持并行...
例如,LongAdder是一个线程安全的累加器,它在高并发的情况下,相比于传统的AtomicInteger提供了更高的性能。这是因为LongAdder在内部使用了分段数组来分散热点,从而减少了高并发下的竞争程度。此外,...
**JDK8中文帮助文档详解** JDK8(Java Development Kit 8)是Java编程语言的一个重要版本,它带来了许多重大的...通过深入理解和熟练运用这些知识点,开发者能够更好地利用JDK8的功能,编写出高效、简洁的Java代码。
API(Application Programming Interface)是Java平台提供的一系列预先定义好的类和方法,程序员可以调用这些类和方法来实现特定功能,而无需从零开始编写所有代码。在JDK 1.8的API中,我们可以找到以下关键知识点:...
4. **默认方法**:接口在Java 8中新增了默认方法,这使得接口可以提供默认实现,而不必强制实现类覆盖该方法。这对于扩展接口功能非常有用,同时也保持了向后兼容性。 5. **日期和时间API**:Java 8中引入了全新的...
4. **新内建类型**:引入了`int`的窄化版本`byte`和`short`,以及新的数值类型`java.lang.LongAdder`,提供了高并发场景下的性能提升。 5. **类型推断增强**:编译器在编译时能更好地推断泛型的实际类型,简化了...
《Java语言规范,Java SE 8版》是Java开发者的重要参考文档,它详细...对于开发者来说,深入理解和掌握Java 8的新特性,将有助于编写出更高效、更优雅的代码。阅读《Java语言规范,Java SE 8版》是掌握这些知识的关键。