网站开发下载功能如何实现,想创业去哪里找项目,英文网站设计公司,网站开发组合 所有组合java 反射操作字段我一直很乐于深入研究多线程编程的细节#xff0c;并且尽管阅读了多年的CPU内存一致性模型#xff0c;无等待和无锁算法#xff0c;Java内存模型#xff0c;实践中的Java并发性等知识#xff0c;但我总是很喜欢。等等-我仍然会创建多线程编程错误。 总是… java 反射操作字段 我一直很乐于深入研究多线程编程的细节并且尽管阅读了多年的CPU内存一致性模型无等待和无锁算法Java内存模型实践中的Java并发性等知识但我总是很喜欢。等等-我仍然会创建多线程编程错误。 总是令人惊奇的谦卑经历使我想起这个问题有多复杂。 如果您已经阅读过JMM那么您可能会记得他们加强的领域之一是保证构造函数完成后最终字段的可见性。 例如 public class ClassA {public final String b;public ClassA(String b) {this.b b;}
}
...
ClassA x new ClassA(hello); JMM指出每个线程甚至构成ClassA实例x的线程除外都将 始终将 xb视为“ hello”并且永远不会看到null值参考字段的默认值。 真是太好了 这意味着我们可以通过将字段标记为final来创建不可变对象并且任何构造的实例都可以自动在线程之间共享而无需进行其他工作来保证内存可见性。 不利的一面是如果未将ClassA.b标记为final那么您将没有此类保证。 其他线程可能会观察到xb 空结果如果未使用其他“安全发布”机制来获得可见性 当他们创建新的JMM时每个人都喜欢的JCP成员Doug Lea创建了一个食谱以帮助JVM开发人员实现新的内存模型规则。 如果阅读此内容那么您将看到“规则”状态即JIT编译器应在构造函数返回之前立即发出StoreStore内存屏障。 StoreStore障碍是一种“内存围栏”。 如果在汇编指令中发出该信息则意味着在对栅栏进行重新排序之前 在栅栏之前出现的内存写之前不能对内存进行任何写存储操作。 请注意它并没有说明读取内容它们可以沿任一方向“跳”栅栏。 那么这是什么意思 如果考虑一下在调用构造函数时编译器会执行的操作那么很好 String x new ClassA(hello);gets broken down in to pseudo-code steps of:1. pointer_to_A allocate memory for ClassA (mark word, class object pointer, one reference field for String b)
2. pointer_to_A.whatever class meta data ...
3. pointer_to_A.b address of hello string
4. emit a StoreStore memory barrier per the JMM
5. x pointer_to_A 步骤4的StoreStore屏障可确保任何写入例如类元数据和对字段b的写入都不会在步骤5中对x进行重新排序。这可以确保x是否对其他任何线程都是可见的-没有StoreStore内存屏障的情况下其他线程也无法看到x。如果没有StoreStore内存屏障则可以对第3步和第5步进行重新排序并且在写入xb和另一个cpu之前可能会显示对x的主内存写入内核可以观察到pointer_to_A.b为0空这将违反JMM。 好消息 但是如果您看一看该菜谱就会发现一些有趣的事情1很多人在许多处理器体系结构上编写JVM 2x86上的所有*存储屏障都是无操作的除了StoreLoad屏障 这意味着在x86上上面的此StoreStore内存屏障为空操作因此不会为此发出任何程序集。 什么也没做 这是因为x86的内存模型是强大的 “总存储排序”TSO。 X86确保观察到所有内存写入就像它们都是以相同顺序进行的一样。 因此由于TSO的原因写入5永远不会出现在任何其他线程的3之前并且不需要发出内存隔离。 其他cpu体系结构的内存模型较弱无法保证这种性能因此需要StoreStore内存围墙。 请注意较弱的内存模型虽然可能更难编程或较不直观但通常要快得多因为cpu可以对事物进行重新排序以更有效地使用缓存写入并减少缓存一致性工作。 显然您应该继续按照JMM编写正确的代码。 但是这也意味着不幸或幸运的是如果您在x86上运行忘记它不会导致错误……就像我在工作中所做的那样。 为了真正地钻研这个家并确保没有食谱中可能没有描述的其他副作用我按此处所述运行了x86程序集输出程序并捕获了为ClassA调用构造函数的输出最后一个在引用类型字段和ClassB的构造函数该类与ClassA相同除了在类成员上没有final关键字之外。 x86程序集的输出是相同的 。 因此从JIT角度来看在x86非钛合金非arm等上final关键字没有任何影响。 如果您想知道汇编代码的外观则如下所示。 请注意没有任何锁定说明。 当Oracle的7u25 JRE发出x86 StoreLoad内存隔离栅时它是通过发出锁addl $ 0x0rsp来完成的该锁只会向堆栈指针添加零无操作 但由于其被锁定因此具有完全栅栏符合StoreLoad栅栏的条件。 x86中有几种导致完全隔离的效果的方法这些方法在OpenJDK邮件列表中进行了讨论。 他们观察到至少在nehelem intel上锁添加0是最紧凑/有效的空间。 0x00007f152c020c60: mov %eax,-0x14000(%rsp)0x00007f152c020c67: push %rbp0x00007f152c020c68: sub $0x20,%rsp ;*synchronization entry; - com.argodata.match.profiling.FinalConstructorMain::callA-1 (line 60)0x00007f152c020c6c: mov %rdx,(%rsp)0x00007f152c020c70: mov %esi,%ebp0x00007f152c020c72: mov 0x60(%r15),%rax0x00007f152c020c76: mov %rax,%r100x00007f152c020c79: add $0x18,%r100x00007f152c020c7d: cmp 0x70(%r15),%r100x00007f152c020c81: jae 0x00007f152c020cd60x00007f152c020c83: mov %r10,0x60(%r15)0x00007f152c020c87: prefetchnta 0xc0(%r10)0x00007f152c020c8f: mov $0x8356f3d0,%r11d ; {oop(com/argodata/match/profiling/FinalConstructorMain$ClassA)}0x00007f152c020c95: mov 0xb0(%r11),%r100x00007f152c020c9c: mov %r10,(%rax)0x00007f152c020c9f: movl $0x8356f3d0,0x8(%rax) ; {oop(com/argodata/match/profiling/FinalConstructorMain$ClassA)}0x00007f152c020ca6: mov %r12d,0x14(%rax) ;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA0 (line 60)0x00007f152c020caa: mov %ebp,0xc(%rax) ;*putfield a; - com.argodata.match.profiling.FinalConstructorMain$ClassA::6 (line 17); - com.argodata.match.profiling.FinalConstructorMain::callA6 (line 60)0x00007f152c020cad: mov (%rsp),%r100x00007f152c020cb1: mov %r10d,0x10(%rax) ;*new ; - com.argodata.match.profiling.FinalConstructorMain::callA0 (line 60)0x00007f152c020cb5: mov %rax,%r100x00007f152c020cb8: shr $0x9,%r100x00007f152c020cbc: mov $0x7f152b765000,%r110x00007f152c020cc6: mov %r12b,(%r11,%r10,1) ;*synchronization entry; - com.argodata.match.profiling.FinalConstructorMain::callA-1 (line 60)0x00007f152c020cca: add $0x20,%rsp0x00007f152c020cce: pop %rbp0x00007f152c020ccf: test %eax,0x9fb932b(%rip) # 0x00007f1535fda000; {poll_return}0x00007f152c020cd5: retq 0x00007f152c020cd6: mov $0x8356f3d0,%rsi ; {oop(com/argodata/match/profiling/FinalConstructorMain$ClassA)}0x00007f152c020ce0: xchg %ax,%ax0x00007f152c020ce3: callq 0x00007f152bfc51e0 ; OopMap{[0]Oop off136};*new ; - com.argodata.match.profiling.FinalConstructorMain::callA0 (line 60); {runtime_call}0x00007f152c020ce8: jmp 0x00007f152c020caa ;*new; - com.argodata.match.profiling.FinalConstructorMain::callA0 (line 60)0x00007f152c020cea: mov %rax,%rsi0x00007f152c020ced: add $0x20,%rsp0x00007f152c020cf1: pop %rbp0x00007f152c020cf2: jmpq 0x00007f152bfc8920 ; {runtime_call} 参考 x86上的Java final字段是否没有操作 来自我们的JCG合作伙伴史蒂夫·阿什Steve Ash来自“多杯咖啡”博客。 翻译自: https://www.javacodegeeks.com/2013/11/java-final-fields-on-x86-a-no-op.htmljava 反射操作字段