`
budairenqin
  • 浏览: 201957 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

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

伪共享的样子:
Java view:
public class VolatileLong {
		volatile long v = 0L;
}

Memory view:
...–––-)(––––HV––––HV–––)(–––...

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

jdk6中的解决办法:
Java view:
public class VolatileLong {
		volatile long p0, p1, p2, p3, p4, p5, p6;
		volatile long v = 0L;
		volatile long q0, q1, q2, q3, q4, q5, q6;
}

Memory view:
...–––-)(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的ConcurrentHashMapV8http://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 view:
// jdk8新特性,Contended注解避免false sharing
// Restricted on user classpath
// Unlock: -XX:-RestrictContended
@sun.misc.Contended
public class VolatileLong {
		volatile long v = 0L;
}


Memory view:
...–––-)(******HV******)(–––...

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

jdk8中已经使用sun.misc.Contended的地方:
src/share/classes/java/util/concurrent/ConcurrentHashMap.java
2458: @sun.misc.Contended static final class CounterCell {

src/share/classes/java/util/concurrent/Exchanger.java
310: * bookkeeping. Padded via @sun.misc.Contended to reduce m
313: @sun.misc.Contended static final class Node {

src/share/classes/java/util/concurrent/ForkJoinPool.java 161:@sun.misc.Contended
643: @sun.misc.Contended

src/share/classes/java/util/concurrent/atomic/Striped64.java
55: * (via @sun.misc.Contended) to reduce cache contention. Pa
119: @sun.misc.Contended static final class Cell {

src/share/classes/java/lang/Thread.java
2004: @sun.misc.Contended("tlr")
2008: @sun.misc.Contended("tlr")
2012: @sun.misc.Contended("tlr")



最后,贴上测试代码,感兴趣的各自测试吧
public class FalseSharing implements Runnable {

	public final static int NUM_THREADS = 4; // change
	public final static long ITERATIONS = 500L * 1000L * 1000L;
	private final int arrayIndex;

	private static VolatileLong3[] longs = new VolatileLong3[NUM_THREADS];
	static {
		for (int i = 0; i < longs.length; i++) {
			longs[i] = new VolatileLong3();
		}
	}

	public FalseSharing(final int arrayIndex) {
		this.arrayIndex = arrayIndex;
	}

	public static void main(final String[] args) throws Exception {
		long start = System.nanoTime();
		runTest();
		System.out.println("duration = " + (System.nanoTime() - start));
	}

	private static void runTest() throws InterruptedException {
		Thread[] threads = new Thread[NUM_THREADS];

		for (int i = 0; i < threads.length; i++) {
			threads[i] = new Thread(new FalseSharing(i));
		}

		for (Thread t : threads) {
			t.start();
		}

		for (Thread t : threads) {
			t.join();
		}
	}

	public void run() {
		long i = ITERATIONS + 1;
		while (0 != --i) {
			longs[arrayIndex].value = i;
		}
	}

	public final static class VolatileLong {
		public volatile long value = 0L;
	}

	// long padding避免false sharing
	// 按理说jdk7以后long padding应该被优化掉了,但是从测试结果看padding仍然起作用
	public final static class VolatileLong2 {
		volatile long p0, p1, p2, p3, p4, p5, p6;
		public volatile long value = 0L;
		volatile long q0, q1, q2, q3, q4, q5, q6;
	}

	// jdk8新特性,Contended注解避免false sharing
	// Restricted on user classpath
	// Unlock: -XX:-RestrictContended
	@sun.misc.Contended
	public final static class VolatileLong3 {
		public volatile long value = 0L;
	}
}


我机器上的测试结果:
VolatileLong: duration = 29594765000
VolatileLong2:duration = 7234555000
VolatileLong3:duration = 7167475000


测试代码来自http://ifeve.com/falsesharing/,稍有改动
分享到:
评论
2 楼 budairenqin 2014-09-15  
liuInsect 写道
      volatile long p0, p1, p2, p3, p4, p5, p6; 
        public volatile long value = 0L; 
        volatile long q0, q1, q2, q3, q4, q5, q6; 
这里 为什么是 13 * 8 个字节 还不是 (7+1)*8?  8*8 =64不是正好是一个cache line么?

是15*8,因为用7个下标保证了会有56个字节填充在数值的任何一边,56字节的填充+8字节的long数值正好装进一行64字节的缓存行。
1 楼 liuInsect 2014-05-21  
      volatile long p0, p1, p2, p3, p4, p5, p6; 
        public volatile long value = 0L; 
        volatile long q0, q1, q2, q3, q4, q5, q6; 
这里 为什么是 13 * 8 个字节 还不是 (7+1)*8?  8*8 =64不是正好是一个cache line么?

相关推荐

    sun.misc.BASE64Decoder(Android Base64Jar包以及Java源代码)

    sun.misc.BASE64Decoder 其中包括 Android Base64Jar包 以及Java源代码 sun.misc.BASE64Decoder 其中包括 Android Base64Jar包 以及Java源代码 sun.misc.BASE64Decoder 其中包括 Android Base64Jar包 以及...

    java开发 sun.misc.BASE64Decoder.jar包下载

    java开发 sun.misc.BASE64Decoder.jar包下载 java开发 sun.misc.BASE64Decoder.jar包下载

    sun.misc.BASE64Decoder和sun.misc.BASE64Encoder不可用已解决

    冲浪后发现JDK中的lib\tools.jar和JRE中的lib\rt.jar已从Java SE 9中删除,也就是1.8版本后的jdk已经不再支持sun.misc.BASE64Decoder和sun.misc.BASE64Encoder。 这些JAR中可用的类和资源现在以文件中的内部格式存储...

    sun.misc.BASE64Encoder.jar包

    如果你的项目依赖于`sun.misc.BASE64Encoder`和`sun.misc.BASE64Decoder`,你应该尽快迁移到`java.util.Base64`,以确保代码的兼容性和长期稳定性。如果因为某些原因必须使用`sun.misc`包(尽管不推荐),你可能需要...

    sun.misc.BASE64Encoder源码及jar包

    在Java编程语言中,`sun.misc.BASE64Encoder`和`BASE64Decoder`是用于进行Base64编码和解码的内部类,它们属于`sun.misc`包,这是一个非公开(非标准)的Java库。`sun.misc`包中的类主要用于JVM内部使用,因此在官方...

    sun.misc.base64decoder.jar下载

    在MyEclipse中编写Java代码时,用到了BASE64Decoder,import sun.misc.BASE64Decoder;可是Eclipse提示:  Access restriction: The type BASE64Decoder is not accessible due to restriction on required library...

    sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;

    总的来说,尽管`sun.misc.BASE64Decoder`和`BASE64Encoder`在某些老项目中可能存在,但现代Java开发应尽量避免依赖这些类,转而使用标准的`java.util.Base64`模块,以确保代码的稳定性和可维护性。对于那些仍然需要...

    RSA加密JAVA实现+sun.misc.BASE64Decoder.jar

    这个Java实现的示例提供了RSA加密和解密的功能,并且结合了`sun.misc.BASE64Decoder.jar`来处理Base64编码,使得加密后的密文能够以可读的形式存储和传输。 首先,RSA的核心原理基于大数因子分解的困难性。每个RSA...

    sun.misc.BASE64Encoder 加密源码+完整包.rar

    在Java编程语言中,`sun.misc.BASE64Encoder` 和 `sun.misc.BASE64Decoder` 是两个用于Base64编码和解码的内部类,它们位于`sun.misc`包下。Base64是一种用于在网络上传输二进制数据的文本编码方式,它将任意的字节...

    JDK8中sun.misc包下的UnSafe类

    JDK8中sun.misc包下的UnSafe类,想查看源码的就拿走,没积分的请与我联系!xtfggef@gmail.com

    JDK8中sun.misc下UnSafe类源代码 UnSafe.java

    《深入解析JDK8中的sun.misc.UnSafe类》 在Java编程中,sun.misc.UnSafe类是一个非常特殊的存在。这个类在JDK8中扮演着一个核心的角色,它提供了对Java语言规范中未公开的底层操作的访问。尽管UnSafe类并非设计为...

    sun.misc.BASE64Encoder 找不到

    在Java编程中,`sun.misc.BASE64Encoder` 类曾是Java标准库早期版本中用于进行Base64编码的一个工具类。然而,由于这个类属于Sun Microsystems的内部实现细节,自Java 9开始,它被标记为废弃,并在后续版本中逐步...

    sun.misc.BASE64Decoder

    在Java编程语言中,`sun.misc.BASE64Decoder`是一个内置的类,它主要用于将Base64编码的数据解码为原始字节。Base64是一种常见的数据编码方式,尤其在网络传输或者存储二进制数据时,因为许多文本格式(如JSON、XML...

    sun.misc.BASE64Decoder.jar

    《深入解析:Java中的sun.misc.BASE64Decoder及其在Java 8后的变化》 在Java编程语言中,`sun.misc.BASE64Decoder`是用于解码Base64编码字符串的一个类,它属于`sun.misc`包,这个包包含了Java标准库中的一些非公开...

    解决sun.misc.URLClassPath自动Debug缘故

    在进行Java项目的开发过程中,尤其是使用集成开发环境(IDE)如Eclipse时,开发者可能会遇到一个较为罕见但又令人困惑的问题:在调试模式下启动项目时,程序会自动跳转至`sun.misc.URLClassPath`类中进行断点调试。...

    sun.misc.BASE64Decoder.jar最新

    sun.misc.BASE64Decoder.jar sun.misc.BASE64Decoder.jar sun.misc.BASE64Decoder.jar sun.misc.BASE64Decoder.jar

    sun.misc.BASE64Decoder.zip

    《深入解析Java 7中的sun.misc.BASE64Decoder》 在Java编程中,`sun.misc.BASE64Decoder`是Java 7版本中一个用于解码Base64编码的数据的类。Base64是一种广泛使用的编码方式,它将任意二进制数据转换为可打印的...

Global site tag (gtag.js) - Google Analytics