写点什么

druid 源码阅读 5——讨论下 druid 为什么不用 AtomicLong

作者:张大彪
  • 2022 年 5 月 14 日
  • 本文字数:4876 字

    阅读完需:约 16 分钟

在源码阅读 3 中,我们看到这么一个细节:

对于原子计数,如果是业务开发的话,我会用:

private volatile AtomicLong                    recycleErrorCount         = new AtomicLong(0L);
复制代码

复制代码

结果 druid 的源码是这么用的:

//声明原始变量private volatile long                    recycleErrorCount         = 0L;//声明一个原始的updaterprotected 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;
@Datapublic 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_scopejava.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                          0Instance size: 24 bytesSpace 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 0Instance size: 24 bytesSpace 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 bytesSpace 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

用户头像

张大彪

关注

还未添加个人签名 2018.04.25 加入

还未添加个人简介

评论

发布
暂无评论
druid 源码阅读 5——讨论下druid为什么不用AtomicLong_张大彪_InfoQ写作社区