大厂面试题
大厂面试题

请描述synchronized和reentrant lock的底层实现,以及重入的底层原理

synchronized

java 代码级别的代码实现 synchronized

class文件 中通过 monitorenter monitorexit 两条Jvm的汇编指令实现

Jvm执行过程中完成锁升级过程

汇编实现 通过 一条汇编指令 lock cmpxchg

reentrant lock

请描述锁的四种状态和升级过程

四种状态

无锁状态 ———> 偏向锁———>轻量级锁(aqs,自旋,无锁)———>重量级锁(线程队列)

升级过程

创建对象后一段时间自动升级成偏向锁

当有一个线程访问时将自己线程指针贴到markword中

当有两个线程竞争时升级成轻量级锁,jdk1.6以后添加了自适应自旋,通过aqs进行操作

当自旋次数过多,访问线程数量过多,生成重量级锁,向操作系统老大申请资源

CAS的ABA问题如何解决

version

请谈一下AQS,为什么AQS底层是CAS + volatile

AQS中的state 的volatile修饰的

在内部维护了一个队列(双向链表)在没有抢到锁的时候,向这个链表的尾部节点插值,需要进行cas操作

谈一下你对volatile 的理解

解决了线程之前可见性和禁止指令重排的维问题

volatile的可见性和禁止指令重排是如何实现的

禁止指令重排

在源码体现 volatile

在clas文件 ACC_VOLATILE 标记

在JVM层面 通过内存屏障

loadload

storestore

loadstore

storeload

在JVM规范中 要求虚拟机实现 在volatile操作前后加一个内存屏障

屏障两边的指令不可以进行重排序

hotsport实现

大厂面试题_sed

CAS是什么

compare and swap

又称无锁,自旋锁

请描述一下对象创建的过程

对象在内存中的内存布局

markwork 8个字节

classpointer 4个字节 这里4个字节是因为

data 成员变量

padding 4个字节 补充能被8乘除,提高读取速度

DCL单例为什么加volatile

防止指令重排,拿到半初始化的对象

/**
 * @description: double check lock
 * @program: lock-immortal
 * @author: Mikael
 * @date: 2021-08-04 10:37
 **/

public class DCL {
    private DCL(){}
    private static DCL DCL_;

    public static DCL getDcl(){
        if (DCL_ == null){
            synchronized (DCL.class){
                if (DCL_ == null){
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                DCL_ = new DCL();
                }
            }
        }
        return DCL_;
    }


    public static void main(String[] args) {
        for (int i = 0; i < 10_0000; i++) {
            new Thread(()->{
                System.out.println("DCL.getDcl().hashCode() = " + DCL.getDcl().hashCode());
            }).start();
        }
    }
}

Object o = new Object()在内存种占了多少字节

答案:16个字节

导入jar

  <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
public class CAS {
    public static void main(String[] args) {
//        AtomicInteger atomicInteger = new AtomicInteger();
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

    }
}

运行结果

java.lang.Object 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)                           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

markwork 8个字节

classpointer 4个字节 这里4个字节是因为

padding 4个字节 补充能被8乘除,提高读取速度

java -XX:+PrintCommandLineFlags -version 通过这个参数,可以看见默认传递的参数
大厂面试题_内存屏障_02

因为现在的系统都是64位的,所以一个指针也就是64位 8个字节

UseCompressedClassPointers 这个参数把8个字节压缩成了4个字节

UseCompressedOops 这个参数把普通的对象指针也压缩到4个字节

oop == ordinary object pointer

你了解Thread local吗? Thread local如何解决内存泄漏问题

线程本地变量

请描述一下锁的分类以及在JDK种的应用

强软弱虚应用类型

强引用 堆中对象没有引用指向时回收 normal

软引用 堆中数据满时,回收软引用 soft 一般用于缓存

弱引用 被GC扫描到就会被回收 weak 一般用于一次性数据

虚引用 管理堆外内存 phantom