druid 源码阅读 5——讨论下 druid 为什么不用 AtomicLong
作者:张大彪
- 2022 年 5 月 14 日
本文字数:4876 字
阅读完需:约 16 分钟
在源码阅读 3 中,我们看到这么一个细节:
对于原子计数,如果是业务开发的话,我会用:
private volatile AtomicLong recycleErrorCount = new AtomicLong(0L);
复制代码
复制代码
结果 druid 的源码是这么用的:
//声明原始变量
private volatile long recycleErrorCount = 0L;
//声明一个原始的updater
protected static final AtomicLongFieldUpdater<DruidDataSource> recycleErrorCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidDataSource.class, "recycleErrorCount");
复制代码
为什么会这么用呢?这篇文章思考下对应的好处。我把我能想到的好处写在这篇文章中。
1、原始类型比包装类型占用空间更小。
为了对比对象与原始类型占用空间大小的差异,翻阅了这篇文章。https://www.cnblogs.com/rickiyang/p/14206724.html
得到一个粗浅的结论:
volatile long = 8 bytes;
AtomicLong = 8 bytes (volatile long) + 16bytes(对象头) + 8 bytes(引用) = 32 bytes
节约了大概 24 字节的存储空间。
对于 recycleErrorCountUpdater , 是一个 static 变量,只会生命一次。如果不是 static 变量的话,估计会不会节省内存。经过文章中 JOL 的测试代码分析结果如下:
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import org.openjdk.jol.info.ClassLayout;
import lombok.Data;
@Data
public class Test {
private volatile AtomicLong recycleErrorCount = new AtomicLong(0L);
private volatile long originalRecycleErrorCount = 0L;
//声明一个原始的updater
protected static final AtomicLongFieldUpdater<Test> recycleErrorCountUpdater
= AtomicLongFieldUpdater.newUpdater(Test.class, "originalRecycleErrorCount");
public static void main(String[] args) {
Test instance = new Test();
ClassLayout classLayout = ClassLayout.parseInstance(instance.getRecycleErrorCount());
System.out.println(classLayout.toPrintable());
System.out.println("====================================================================================================================================");
ClassLayout classLayout2 = ClassLayout.parseInstance(instance.getOriginalRecycleErrorCount());
System.out.println(classLayout2.toPrintable());
System.out.println("====================================================================================================================================");
ClassLayout classLayout3 = ClassLayout.parseInstance(Test.recycleErrorCountUpdater);
System.out.println(classLayout3.toPrintable());
}
}
复制代码
运行结果:
/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=64351:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/tools.jar:/Users/zhdd99/KuaishouProjects/kim/fundation/helloworld/target/classes:/Users/zhdd99/.m2/repository/org/openjdk/jol/jol-core/0.14/jol-core-0.14.jar:/Users/zhdd99/.m2/repository/com/google/guava/guava/28.1-jre-kwai5/guava-28.1-jre-kwai5.jar:/Users/zhdd99/.m2/repository/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar:/Users/zhdd99/.m2/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/Users/zhdd99/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/zhdd99/.m2/repository/org/checkerframework/checker-qual/2.8.1/checker-qual-2.8.1.jar:/Users/zhdd99/.m2/repository/com/google/errorprone/error_prone_annotations/2.3.2/error_prone_annotations-2.3.2.jar:/Users/zhdd99/.m2/repository/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar:/Users/zhdd99/.m2/repository/org/codehaus/mojo/animal-sniffer-annotations/1.18/animal-sniffer-annotations-1.18.jar:/Users/zhdd99/.m2/repository/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar:/Users/zhdd99/.m2/repository/org/antlr/ST4/4.3/ST4-4.3.jar:/Users/zhdd99/.m2/repository/org/antlr/antlr-runtime/3.5.2/antlr-runtime-3.5.2.jar:/Users/zhdd99/.m2/repository/net/coobird/thumbnailator/0.4.11/thumbnailator-0.4.11.jar:/Users/zhdd99/.m2/repository/org/apache/commons/commons-lang3/3.10/commons-lang3-3.10.jar:/Users/zhdd99/.m2/repository/cn/hutool/hutool-all/5.4.0/hutool-all-5.4.0.jar:/Users/zhdd99/.m2/repository/com/google/code/gson/gson/2.8.2/gson-2.8.2.jar:/Users/zhdd99/.m2/repository/org/projectlombok/lombok/1.18.24/lombok-1.18.24.jar Test sakfjaksjfkasjfk
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
java.util.concurrent.atomic.AtomicLong object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 93 53 00 f8 (10010011 01010011 00000000 11111000) (-134196333)
12 4 (alignment/padding gap)
16 8 long AtomicLong.value 0
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
====================================================================================================================================
java.lang.Long object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) f5 22 00 f8 (11110101 00100010 00000000 11111000) (-134208779)
12 4 (alignment/padding gap)
16 8 long Long.value 0
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
====================================================================================================================================
java.util.concurrent.atomic.AtomicLongFieldUpdater$CASUpdater object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 6f 9e 00 f8 (01101111 10011110 00000000 11111000) (-134177169)
12 4 java.lang.Class CASUpdater.cclass (object)
16 8 long CASUpdater.offset 16
24 4 java.lang.Class CASUpdater.tclass (object)
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Process finished with exit code 0
复制代码
运行结果:
AtomicLong 对象占用空间:24 bytes
Long 占用空间:24 bytes
那个 static 的 updater : 32 bytes
以上三个只是对象空间,别忘了还有个引用,是 8bytes
划线
评论
复制
发布于: 刚刚阅读数: 4
张大彪
关注
还未添加个人签名 2018.04.25 加入
还未添加个人简介
评论