转载自:http://www.myexception.cn/program/1630142.html
Java8中使用sun.misc.Contended注解来避免伪共享(false sharing)。关于伪共享这个概念,可以先参照http://ifeve.com/falsesharing/
伪共享的例子:
如果有两个VolatileLong对象,会被load到同一个缓存行里面,如果一个线程要修改对象1,另一个线程同时要修改对象2,此时就要面对伪共享问题(core1对缓存行中对象1的修改,导致core2中同一缓存行失效,即缓存的对象2需要重新load)。
jdk6中的解决办法:
上面的方式也就是long padding来避免伪共享,使用无关数据来填充缓存行,使得两个VolatileLong对象不会load到同一个缓存行里面。无锁并发框架Disruptor正是采用的这种方式。
long padding的解决办法不怎么优雅,并且在jdk7某个版本以后能会优化掉long padding,详细参考 http://ifeve.com/false-sharing-java-7/ 。但是java8已经给出了官方的解决办法,就是sun.misc.Contended注解。
这里,JVM就不会将被Contended注解的两个VolatileLong对象load到同一个缓存行里面。要注意的是user classpath使用此注解默认是无效的,需要在jvm启动时设置-XX:-RestrictContended。(不太理解。。。经测试,自己应用程序的sun.misc.Contended注解的类需要-XX:-RestrictContended才能生效,是不是对jdk源码中的sun.misc.Contended不需要上述注解就可以生效了?)
jdk8中有很多地方已经使用了sun.misc.Contended:
java/util/concurrent/ConcurrentHashMap.java
java/util/concurrent/Exchanger.java
Java8中使用sun.misc.Contended注解来避免伪共享(false sharing)。关于伪共享这个概念,可以先参照http://ifeve.com/falsesharing/
伪共享的例子:
如果有两个VolatileLong对象,会被load到同一个缓存行里面,如果一个线程要修改对象1,另一个线程同时要修改对象2,此时就要面对伪共享问题(core1对缓存行中对象1的修改,导致core2中同一缓存行失效,即缓存的对象2需要重新load)。
jdk6中的解决办法:
上面的方式也就是long padding来避免伪共享,使用无关数据来填充缓存行,使得两个VolatileLong对象不会load到同一个缓存行里面。无锁并发框架Disruptor正是采用的这种方式。
long padding的解决办法不怎么优雅,并且在jdk7某个版本以后能会优化掉long padding,详细参考 http://ifeve.com/false-sharing-java-7/ 。但是java8已经给出了官方的解决办法,就是sun.misc.Contended注解。
这里,JVM就不会将被Contended注解的两个VolatileLong对象load到同一个缓存行里面。要注意的是user classpath使用此注解默认是无效的,需要在jvm启动时设置-XX:-RestrictContended。(不太理解。。。经测试,自己应用程序的sun.misc.Contended注解的类需要-XX:-RestrictContended才能生效,是不是对jdk源码中的sun.misc.Contended不需要上述注解就可以生效了?)
jdk8中有很多地方已经使用了sun.misc.Contended:
java/util/concurrent/ConcurrentHashMap.java
java/util/concurrent/Exchanger.java