专栏首页歪歪梯Club并发基石-Markword与锁升级

并发基石-Markword与锁升级

synchronized

synchronized关键字是java提供的互斥锁关键字,我们常说的互斥锁一般都是非自旋锁,即竞争不到锁的线程会进入阻塞状态知道被唤醒 今天我们来讲讲java中用来对synchronized进行优化的三种锁,同时会介绍markword对象头 目前我在网上搜到的十几篇博客讲的都有问题,可能有写对的我没搜到. 很多人不经过验证直接把markOop.hpp中的JavaThread*当成ThreadId这是错误的,实际是java线程在C语言的指针 并且未计算过hashCode和计算过hashCode的情况也是不一样的 本篇博客最后会展示使用jol工具,读取展示对象头的结果进行验证 附上openjdk的markOop.hpp链接

对象头Markword

对象头是java将对象比较常用和重要的运行时数据,如hashCode、gc标识、存活年龄等等进行集中存储的一组数据 占据8个字节,以下只讨论目前比较常见的64位的情况

偏向锁、轻量级锁、重量级锁介绍

64bit下各锁状态的Markword格式

64 bits:
  --------
  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
  size:64 ----------------------------------------------------->| (CMS free block)

  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
 [ptr             | 00]  locked             ptr points to real header on stack
 [header      | 0 | 01]  unlocked           regular object header
 [ptr             | 10]  monitor            inflated lock (header is wapped out)
 [ptr             | 11]  marked             used by markSweep to mark an object

32bit下各锁状态的Markword格式

32 bits:
  --------
  hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
  JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
  size:32 ------------------------------------------>| (CMS free block)
  PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)

也就是对象头的最后两位,是作为锁的状态标志 00---轻量锁 01---偏向锁/无锁 10---重量锁 11---GC标记 偏向锁状态和无锁状态通过区分对象头倒数第三位来确定,0代表无锁,1代表偏向锁 注意,未计算hashCode的对象的初始状态为匿名偏向锁(线程指针为0,代表无线程获取)而非无锁

偏向锁与无锁

java中对于锁的实际获取依赖于UnSafe调用native方法去实现不同操作系统上的cas原语操作 如果一个对象,在每次作业的运行始终处于单一线程,那每次对于锁的检测、获取和释放都会对性能造成不小的消耗 于是java引入了偏向锁 当一个处于匿名偏向锁状态的对象,第一次被一个线程竞争时,其对象头会被标记为偏向锁,同时存储其线程指针 接下来每次该线程对该锁的获取都不需要经过不必要的cas判断锁资源从而优化了性能,这也是偏向的由来

匿名偏向锁状态的对象如果计算了hashCode,则会变为无锁状态。hashCode存在markword,并且接下来不会再进去偏向锁

匿名偏向锁状态的对象被获取时,进入非匿名偏向锁状态,markword存储持有者的java线程在操作系统的C语言指针

无锁状态下的对象被获取时,会直接跳到轻量级锁(因为偏向锁下markword没有记录hashCode,没办法存储hashCode,而轻量级锁的下面讲)

非匿名偏向锁状态的对象计算了hashCode以后,会直接进入重量级锁,此时的重量级锁会(重量级锁的下面讲)

开启偏向锁的支持需要添加两个虚拟机参数

-XX:+UseBiasedLocking
-XX:BiasedLockingStartupDelay=0

第一个参数是开启偏向锁 第二个参数是指定立即开启,因为默认偏向锁的开启时在虚拟机运行后延时5秒 如果没有线程竞争,非匿名偏向锁偏向锁释放后会变回匿名偏向锁状态

锁升级-轻量级锁

当一个对象处于非匿名偏向锁状态下,如果有别的线程过来竞争,另一个线程尝试竞争锁,竞争失败并给予jvm一个竞争的信号以后进入自旋(不断尝试获取锁) 接下来在持有该锁的线程执行来到安全点时,会触发stop the world并将膨胀为轻量级锁 轻量级锁会创建一份锁记录(Lock Record)在当前持有他的线程的线程栈里 LockRecord中包含一个owner属性指向锁对象,而锁对象的markword中也会保存一个执行该LockRecord的指针

这时的竞争就是轻量级锁的竞争了,轻量级锁的竞争时,竞争锁的线程会在一个周期时间内不断的自旋获取锁,如果获取失败就会进入阻塞并将markword的锁标记标记为10(重量级锁)

因为LockRecord复制了markword,所以在执行同步块时并不去关注markword,只有到了释放时

1.锁对象的markword升级为了重量级锁,将锁对象升级为重量级锁,锁对象的markword存储一个指向一个由操作系统实现的mutex互斥变量,唤醒阻塞的竞争线程

2.markword没变化,释放锁,对象锁恢复到无锁状态(如果LockRecord记录的是偏向锁,则恢复到匿名偏向锁,否则恢复到无锁状态)

锁升级-重量级锁

当对象来到重量级锁以后,新被从竞争队列挑选出来一部分竞争锁的线程队列会一起竞争锁 最终竞争到锁的一个线程会继续运行,竞争失败的线程进入阻塞队列 处于执行状态的线程执行完同步代码块后,会释放锁并唤醒阻塞队列中的线程 将他们加入新的挑选出来的竞争锁的线程队列,并重新竞争锁,重复以上操作 因为需要阻塞和唤醒线程,所以需要从用户态到系统态切换,所以重量级锁下的系统开销很大

代码验证

        Thread currentThread = Thread.currentThread();
        System.out.println("threadId : "+Long.toBinaryString(currentThread.getId()));
        Object o = new Object();
        System.out.println("-------------------------------------------------------------------------------------------------------");
        System.out.println("init object info");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");
        synchronized (o) {
            System.out.println("synchronized lock object info");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
            System.out.println("synchronized finished");
            System.out.println("-------------------------------------------------------------------------------------------------------");
        }
        Thread.sleep(2000);
        System.out.println("after synchronized object info");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("binary hashCode : "+Integer.toBinaryString(o.hashCode()));
        System.out.println("-------------------------------------------------------------------------------------------------------");

        System.out.println("after calculate hashcode object info");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");

        synchronized (o) {
            System.out.println("synchronized lock object info");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
            System.out.println("synchronized finished");
            System.out.println("-------------------------------------------------------------------------------------------------------");
        }
        Object o2 = new Object();
        System.out.println("o2 hashCode : "+Long.toBinaryString(o2.hashCode()));
        System.out.println("init lock object2 info");
        System.out.println(ClassLayout.parseInstance(o2).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");
        synchronized (o2) {
            System.out.println("synchronized lock object2 info");
            System.out.println(ClassLayout.parseInstance(o2).toPrintable());
            System.out.println("synchronized finished");
            System.out.println("-------------------------------------------------------------------------------------------------------");
        }
        System.out.println("after lock object2 info");
        System.out.println(ClassLayout.parseInstance(o2).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");
        //计算过hashcode的会直接进入轻量锁

输出结果

threadId : 1
-------------------------------------------------------------------------------------------------------
init object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------
synchronized lock object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 e8 09 01 (00000101 11101000 00001001 00000001) (17426437)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
after synchronized object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 e8 09 01 (00000101 11101000 00001001 00000001) (17426437)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

binary hashCode : 100000111110100010001111000001
-------------------------------------------------------------------------------------------------------
after calculate hashcode object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 c1 23 fa (00000001 11000001 00100011 11111010) (-98320127)
      4     4        (object header)                           20 00 00 00 (00100000 00000000 00000000 00000000) (32)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------
synchronized lock object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           50 f7 c4 02 (01010000 11110111 11000100 00000010) (46462800)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
o2 hashCode : 110101100000011100010111110011
init lock object2 info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631)
      4     4        (object header)                           35 00 00 00 (00110101 00000000 00000000 00000000) (53)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------
synchronized lock object2 info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           50 f7 c4 02 (01010000 11110111 11000100 00000010) (46462800)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
after lock object2 info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631)
      4     4        (object header)                           35 00 00 00 (00110101 00000000 00000000 00000000) (53)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------

多线程竞争

Thread currentThread = Thread.currentThread();
        System.out.println("threadId : "+Long.toBinaryString(currentThread.getId()));
        Object o = new Object();
        System.out.println("-------------------------------------------------------------------------------------------------------");
        System.out.println("init object info");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");

        new Thread() {
            public void run() {
                synchronized (o) {
                    System.out.println("-------------------------------------------------------------------------------------------------------");
                    System.out.println("-------------------------------------------------------------------------------------------------------");
                    System.out.println("another thread id "+Long.toBinaryString(this.getId()));
                    System.out.println("synchronized lock object info");
                    System.out.println(ClassLayout.parseInstance(o).toPrintable());
                    System.out.println("synchronized finished");
                    System.out.println("-------------------------------------------------------------------------------------------------------");
                    System.out.println("------------------------------------------------------------------------------------------------------");
                }
            }
        }.start();

        synchronized (o) {
            System.out.println("synchronized lock object info");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());

            //有锁未计算hashCode状态下计算hashCode

            o.hashCode();
            System.out.println("when synchronized calculate hashcode ");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());

            System.out.println("synchronized finished");
            System.out.println("-------------------------------------------------------------------------------------------------------");
        }
        Thread.sleep(2000);
        System.out.println("after synchronized object info");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("binary hashCode : "+Integer.toBinaryString(o.hashCode()));
        System.out.println("-------------------------------------------------------------------------------------------------------");

        System.out.println("after calculate hashcode object info");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");

        synchronized (o) {
            System.out.println("synchronized lock object info");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
            System.out.println("synchronized finished");
            System.out.println("-------------------------------------------------------------------------------------------------------");
        }
        Object o2 = new Object();
        System.out.println("o2 hashCode : "+Long.toBinaryString(o2.hashCode()));
        System.out.println("init lock object2 info");
        System.out.println(ClassLayout.parseInstance(o2).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");
        synchronized (o2) {
            System.out.println("synchronized lock object2 info");
            System.out.println(ClassLayout.parseInstance(o2).toPrintable());
            System.out.println("synchronized finished");
            System.out.println("-------------------------------------------------------------------------------------------------------");
        }
        System.out.println("after lock object2 info");
        System.out.println(ClassLayout.parseInstance(o2).toPrintable());
        System.out.println("-------------------------------------------------------------------------------------------------------");
        //计算过hashcode的会直接进入轻量锁

输出结果

threadId : 1
-------------------------------------------------------------------------------------------------------
init object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------
synchronized lock object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           ba c4 c4 02 (10111010 11000100 11000100 00000010) (46449850)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

when synchronized calculate hashcode 
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           ba c4 c4 02 (10111010 11000100 11000100 00000010) (46449850)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------
another thread id 1010
synchronized lock object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           ba c4 c4 02 (10111010 11000100 11000100 00000010) (46449850)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------
after synchronized object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 c1 23 fa (00000001 11000001 00100011 11111010) (-98320127)
      4     4        (object header)                           20 00 00 00 (00100000 00000000 00000000 00000000) (32)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

binary hashCode : 100000111110100010001111000001
-------------------------------------------------------------------------------------------------------
after calculate hashcode object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 c1 23 fa (00000001 11000001 00100011 11111010) (-98320127)
      4     4        (object header)                           20 00 00 00 (00100000 00000000 00000000 00000000) (32)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------
synchronized lock object info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           90 f5 ad 02 (10010000 11110101 10101101 00000010) (44955024)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
o2 hashCode : 110101100000011100010111110011
init lock object2 info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631)
      4     4        (object header)                           35 00 00 00 (00110101 00000000 00000000 00000000) (53)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------
synchronized lock object2 info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           90 f5 ad 02 (10010000 11110101 10101101 00000010) (44955024)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

synchronized finished
-------------------------------------------------------------------------------------------------------
after lock object2 info
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 f3 c5 81 (00000001 11110011 11000101 10000001) (-2117733631)
      4     4        (object header)                           35 00 00 00 (00110101 00000000 00000000 00000000) (53)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------------------------------------------------------------------------------------

本文分享自微信公众号 - 歪歪梯Club(bcbkmgzh),作者:歪歪梯

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python网络爬虫并输出excel

    环境是python3.6.5以及PyCharm不得不说,JetBrains做的IDE都很不错,无论是这款PyCharm还是IntelliJ、Goland在形参处...

    歪歪梯
  • ActiveMQ源码分析——生产消息

    创建Session时,第一个传入是否开启事务,第二个传入session提交消费消息的方式 接下来看源码处理,生产者id对象由当前sessionID加上使用内部s...

    歪歪梯
  • ActiveMQ源码分析——消费消息

    请先查看上一篇分析生产消息源码的博客之后再查看本篇 先看看本博客把consumer端分析后完整的activemq流程图

    歪歪梯
  • JSON.stringify() 的 5 个秘密特性

    关于本文译者:@zoomdong译文:https://juejin.im/post/5e842da76fb9a03c854610c7校对者:@Long Xion...

    coder_koala
  • JSON.stringify方法的5个秘密功能

    JSON.stringify()方法将JavaScript对象或值转换为JSON字符串。

    前端知否
  • 常见图片格式详解(三)----JPEG

    JPEG是一种比较成熟的图像有损压缩格式,经过JPEG压缩,图像质量会有所损失,但是,人眼是很不容易分辨出来这种差别的。jpeg图像在质量和存储空间得到了一个相...

    视界音你而不同
  • 手搓一个分布式大气监测系统(四)基于TencentOS Tiny RISC-V开发板打造PM2.5监测终端

    鹅民大气监测项目是一个以腾讯云物联网开发平台为基础起点,并叠加多款云产品后,实现的一个验证型项目。

    Supowang
  • JavaScript 浮点数之迷:大数危机

    在 JavaScript 中浮点数运算时经常出现 0.1+0.2=0.30000000000000004 这样的问题,除了这个问题之外还有一个不容忽视的大数危机...

    五月君
  • 你必须知道的Dockerfile

    本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

    Edison Zhou
  • Hibernate文件配置

    映射需要通过XML的配置文件来完成,这个配置文件尽量统一(xxx.hbm.xml) Hibernate核心的配置:必须的配置、可选的配置、映射文件的引入

    用户3112896

扫码关注云+社区

领取腾讯云代金券