AtomicInteger lazySet与设置
AtomicInteger
的lazySet
和set
方法有什么区别? 文档没有太多关于lazySet
:
最终设置为给定的值。
似乎储值不会立即设定为所需的值,而是预定将来设定一段时间。 但是,这种方法的实际用途是什么? 任何例子?
从错误6275329直接引用:
作为Mustang的最后一个小JSR166后续,我们为Atomic类(AtomicInteger,AtomicReference等)添加了一个“lazySet”方法。 这是一种利用非阻塞数据结构微调代码的有用方法。 语义是保证写操作不会被任何先前的写入重新sorting,但是可能会被后续操作重新sorting(或者等同于其他线程可能不可见),直到发生其他一些易失性写操作或同步操作为止。
主要的用例是为了避免长时间的垃圾留存而将非阻塞数据结构中的节点字段清空; 如果其他线程在一段时间内看到非空值,那么它适用于无害的情况,但是您希望确保结构最终是GCable。 在这种情况下,您可以通过避免空volatile-write的成本获得更好的性能。 对于非基于引用的primefaces,沿着这些行还有一些其他用例,所以在所有的AtomicX类中都支持该方法。
对于那些喜欢用普通多处理机上的机器级别障碍来考虑这些操作的人来说,lazySet提供了一个先行的store-store障碍(在当前的平台上它可能是no-op或者非常便宜的),但是没有store-load barrier (这通常是volatile-write的昂贵部分)。
lazySet可以用于rmw的线程间通信,因为xchg是primefaces的,至于可见性,当writer线程进程修改一个cache线的位置时,reader线程的处理器会在下次读取时看到它,因为intel cpu的cache coherence协议会保证LazySet的作品,但高速caching行将在下次阅读更新,再次,CPU必须足够现代。
http://sc.tamu.edu/systems/eos/nehalem.pdf对于Nehalem是一个多处理器平台,处理器可以“窥探”(窃听)其他处理器访问系统内存的地址总线,到他们的内部caching。; 他们使用这种监听function来保持其内部caching与系统内存和其他互连处理器中的caching保持一致。 如果通过窥探,一个处理器检测到另一个处理器打算写入当前已经caching在共享状态的存储器位置,则窥探处理器将使其caching块无效,迫使其在下一次访问相同的存储器位置时执行caching行填充。
oracle热点jdk for x86 cpu架构 – >
lazySet == unsafe.putOrderedLong == xchg rw(asm指令,作为nehelem intel cpu花费20个周期的软屏障)
在x86(x86_64)上这样的障碍比易失性或AtomicLong getAndAdd更便宜,
在一个生产者中,一个消费者队列场景中,xchg软屏障可以强制生产者线程的lazySet(sequence + 1)之前的代码行发生在消费(处理)新数据的任何消费者线程代码之前消费者线程将需要使用compareAndSet(sequence,sequence + 1)primefaces地检查生产者序列是否增加了一个。
我跟踪了Hotspot源代码,findlazySet到cpp代码的确切映射: http ://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe 。 cpp Unsafe_setOrderedLong – > SET_FIELD_VOLATILE定义 – > OrderAccess:release_store_fence。 对于x86_64,OrderAccess:release_store_fence被定义为使用xchg指令。
你可以看到它在jdk7中的确切定义(doug lea正在为JDK 8开发一些新的东西): http : //hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/ linux_x86 / VM / orderAccess_linux_x86.inline.hpp
您也可以使用hdis来反汇编lazySet代码的程序集。
还有一个相关的问题: 使用xchg的时候我们需要保护吗?
关于lazySet和底层putOrdered的起源和效用的更广泛的讨论可以在这里find: http ://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html
总结一下:lazySet是一个弱的易失性写,因为它作为一个store-store而不是store-load fence。 这可以归结为lazySet被JIT编译成一个MOV指令,不能由编译器重新sorting,而不是用于易失性集合的昂贵的指令。
在读取值时,你总是会做一个易失的读取(无论如何都要用Atomic * .get())。
lazySet为单个写入者提供了一致的易失性写入机制,也就是说,单个写入者使用lazySet增加计数器是完全合法的,多个线程递增相同的计数器将不得不使用CAS解决竞争性写入,这正是发生在primefaces能*为incAndGet的封面。
从Concurrent-atomic软件包总结
lazySet具有写入(赋值)volatilevariables的内存效果,除了它允许重新sorting后续的(而不是先前的)内存操作,而这些操作本身并不会对普通的非易失性写入施加重新sorting约束。 在其他使用上下文中,lazySet可以在为了垃圾收集而将空值清空时应用从不再被访问的引用。
如果你对lazySet很好奇,那么你也应该自己解释一下
对于访问和更新primefaces的记忆效应一般遵循挥发性规则,如Java™语言规范第17.4节所述。
获得读取volatilevariables的记忆效应。
集具有写入(分配)易失性variables的记忆效应。
lazySet具有写入(赋值)volatilevariables的内存效果,除了它允许重新sorting后续的(而不是先前的)内存操作,而这些操作本身并不会对普通的非易失性写入施加重新sorting约束。 在其他使用上下文中,为了垃圾收集的目的,lazySet可以在空值时应用一个永远不会再被访问的引用。
weakCompareAndSet自动读取并有条件地写入一个variables,但不会在sorting之前创build任何发生,所以对于之前或之后读取和写入除weakCompareAndSet的目标之外的任何其他variables不提供保证。 compareAndSet和所有其他读取和更新操作(如getAndIncrement)具有读取和写入易失性variables的内存效果。
这里是我的理解,如果我错了,请纠正我:你可以把lazySet()看作是“semi”volatile:它基本上是一个非易失性variables,由其他线程读取,即由lazySet设置的值可能不可见到其他线程。 但是,当另一个写操作发生时,它会变得不稳定(可能来自其他线程)。 我能想象的lazySet的唯一影响是compareAndGet。 因此,如果使用lazySet(),则其他线程的get()仍然可以获得旧值,但compareAndGet()将始终具有新值,因为它是写入操作。
回复:试图愚弄它 –
您可以将其视为一种将易失性字段视为对特定商店(例如:ref = null;)操作不是易失性的方式。
这并不完全准确,但你可以在“好吧,我真的不在乎”和“嗯,让我想一下”之间作出决定就够了。