Java8中用sun.misc.Contended避免伪共享(false sharing)

转自:http://budairenqin.iteye.com/blog/2048257

关于伪共享这个概念,请先参照http://ifeve.com/falsesharing/ 


伪共享的样子: 
Java代码   收藏代码
  1. Java view:  
  2. public class VolatileLong {  
  3.         volatile long v = 0L;  
  4. }  
  5.   
  6. Memory view:  
  7. ...–––-)(––––HV––––HV–––)(–––...  

我们看到,两个VolatileLong对象被load到了同一个缓存行里面,如果一个线程要修改对象1,另一个线程同时要修改对象2,此时就要面对伪共享这个无形的性能杀手了 

jdk6中的解决办法: 
Java代码   收藏代码
  1. Java view:  
  2. public class VolatileLong {  
  3.         volatile long p0, p1, p2, p3, p4, p5, p6;  
  4.         volatile long v = 0L;  
  5.         volatile long q0, q1, q2, q3, q4, q5, q6;  
  6. }  
  7.   
  8. Memory view:  
  9. ...–––-)(ppppppHVqqqqqq)(–––...  


很多大神的代码都是通过上面的方式也就是long padding来避免伪共享 
例如: 
1.Doug Lea的jsr166中早期的LinkedTransferQueue版本 http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166y/LinkedTransferQueue.java?revision=1.1&view=markup  
2.还是Doug Lea的ConcurrentHashMapV8 http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/ConcurrentHashMapV8.java?revision=1.121&view=markup (在java8中的版本已经用sun.misc.Contended替换long padding) 
3.大名鼎鼎的无锁并发框架Disruptor  https://github.com/LMAX-Exchange/disruptor  
4.等等等... 

long padding的解决办法不怎么优雅,并且在jdk7某个版本以后能会优化掉long padding,尼玛java程序员是有多难啊,想尽了一切办法对付jdk7中的这个优化,详情点击 http://ifeve.com/false-sharing-java-7/  

但是但是...开始使用jdk8的同学注意了,java8已经给出了官方的解决办法... 
就是sun.misc.Contended注解 http://mail.openjdk.java.net/pipermail/hotspot-dev/2012-November/007309.html  

Java代码   收藏代码
  1. Java view:  
  2. // jdk8新特性,Contended注解避免false sharing  
  3. // Restricted on user classpath  
  4. // Unlock: -XX:-RestrictContended  
  5. @sun.misc.Contended  
  6. public class VolatileLong {  
  7.         volatile long v = 0L;  
  8. }  
  9.   
  10.   
  11. Memory view:  
  12. ...–––-)(******HV******)(–––...  

要注意的是user classpath使用此注解默认是无效的,需要在jvm启动时设置-XX:-RestrictContended 

jdk8中已经使用sun.misc.Contended的地方: 
Java代码   收藏代码
  1. src/share/classes/java/util/concurrent/ConcurrentHashMap.java  
  2. 2458@sun.misc.Contended static final class CounterCell {  
  3.   
  4. src/share/classes/java/util/concurrent/Exchanger.java  
  5. 310: * bookkeeping. Padded via @sun.misc.Contended to reduce m  
  6. 313@sun.misc.Contended static final class Node {  
  7.   
  8. src/share/classes/java/util/concurrent/ForkJoinPool.java 161:@sun.misc.Contended  
  9. 643@sun.misc.Contended  
  10.   
  11. src/share/classes/java/util/concurrent/atomic/Striped64.java  
  12. 55: * (via @sun.misc.Contended) to reduce cache contention. Pa  
  13. 119@sun.misc.Contended static final class Cell {  
  14.   
  15. src/share/classes/java/lang/Thread.java  
  16. 2004@sun.misc.Contended("tlr")  
  17. 2008@sun.misc.Contended("tlr")  
  18. 2012@sun.misc.Contended("tlr")  



最后,贴上测试代码,感兴趣的各自测试吧 
Java代码   收藏代码
  1. public class FalseSharing implements Runnable {  
  2.   
  3.     public final static int NUM_THREADS = 4// change  
  4.     public final static long ITERATIONS = 500L * 1000L * 1000L;  
  5.     private final int arrayIndex;  
  6.   
  7.     private static VolatileLong3[] longs = new VolatileLong3[NUM_THREADS];  
  8.     static {  
  9.         for (int i = 0; i < longs.length; i++) {  
  10.             longs[i] = new VolatileLong3();  
  11.         }  
  12.     }  
  13.   
  14.     public FalseSharing(final int arrayIndex) {  
  15.         this.arrayIndex = arrayIndex;  
  16.     }  
  17.   
  18.     public static void main(final String[] args) throws Exception {  
  19.         long start = System.nanoTime();  
  20.         runTest();  
  21.         System.out.println("duration = " + (System.nanoTime() - start));  
  22.     }  
  23.   
  24.     private static void runTest() throws InterruptedException {  
  25.         Thread[] threads = new Thread[NUM_THREADS];  
  26.   
  27.         for (int i = 0; i < threads.length; i++) {  
  28.             threads[i] = new Thread(new FalseSharing(i));  
  29.         }  
  30.   
  31.         for (Thread t : threads) {  
  32.             t.start();  
  33.         }  
  34.   
  35.         for (Thread t : threads) {  
  36.             t.join();  
  37.         }  
  38.     }  
  39.   
  40.     public void run() {  
  41.         long i = ITERATIONS + 1;  
  42.         while (0 != --i) {  
  43.             longs[arrayIndex].value = i;  
  44.         }  
  45.     }  
  46.   
  47.     public final static class VolatileLong {  
  48.         public volatile long value = 0L;  
  49.     }  
  50.   
  51.     // long padding避免false sharing  
  52.     // 按理说jdk7以后long padding应该被优化掉了,但是从测试结果看padding仍然起作用  
  53.     public final static class VolatileLong2 {  
  54.         volatile long p0, p1, p2, p3, p4, p5, p6;  
  55.         public volatile long value = 0L;  
  56.         volatile long q0, q1, q2, q3, q4, q5, q6;  
  57.     }  
  58.   
  59.     // jdk8新特性,Contended注解避免false sharing  
  60.     // Restricted on user classpath  
  61.     // Unlock: -XX:-RestrictContended  
  62.     @sun.misc.Contended  
  63.     public final static class VolatileLong3 {  
  64.         public volatile long value = 0L;  
  65.     }  
  66. }  


我机器上的测试结果: 
Java代码   收藏代码
  1. VolatileLong: duration = 29594765000  
  2. VolatileLong2:duration = 7234555000  
  3. VolatileLong3:duration = 7167475000  


测试代码来自 http://ifeve.com/falsesharing/ ,稍有改动
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值