面试-java常见问题

JVM 配置

  • 程序计数器:当前线程所执行的字节码的行号指示器
  • java虚拟机栈:临时变量
  • 元空间:类常量池,运行时常量池
  • 方法区:类信息,静态变量
  • 堆:对象实例,Sting常量池等

类加载过程

加载->链接(验证+准备+解析)->初始化->使用->卸载

加载:将硬盘中的二进制文件转为内存中的class对象

链接:给静态变量赋初始值,符号引用替换为直接引用

  • 验证:检查载入的class 文件数据正确性。
  • 准备:给类变量(静态变量)分配内存(方法区),直接赋值为最终值。
  • 解析:将常量池内的符号引用替换为直接引用。

初始化:执行类变量(静态变量)的赋值和静态语句块
使用:若是第一次创建对象(对象所属的类没有加载到内存中),先执行初始化操作,再堆上为对象分配空间,所有属性设设置默认值,给实例变量赋值,初始化语句,检查是否有父类,有就先执行父类的构造函数。

GC垃圾回收流程

GC垃圾回收,是对堆内存的一清理。
堆内存:
年轻代:(eden[伊甸园],survior[存活区],vlrtual[伸缩区])
老年代:(tenured[旧生代],vlrtual[伸缩区])
永久代:(1.8后就不存在了,换为了元空间)
在这里插入图片描述

ArrayList是否线程安全?如何线程安全地操作ArrayList?

ArrayList 是线程不安全的,如果需要线程安全的List,可以从采用Vector/Collections.synchronizedList/CopyOnWriteArrayList
Vector: 使用synchronized关键字
Collections.synchronizedList: 内每一个方法都加了synchronized 关键字
CopyOnWriteArrayList: 在写操作的时候总是要复制,将原来的数据复制到新的数组进行操作,任何可变的操作都是通过ReentrantLock 控制并发。

线程不安全的原因:
当多个线程同时对一个数组进行操作时,如果线程1 执行 list[i] = “a” ,i++;线程2执行 list[i] = “b” ,i++;
如果线程同步执行了list[i] = 的操作,在执行i++,那么i+1 就有可能出现空值,list[i]的值同样可能出现被覆盖的情况。所以说ArrayList 线程不安全。

HashMap、TreeMap、LinkedHashMap的区别?

相同点:都是属于Map,都是通过K-V存储,K不允许重复。都是线程不安全的。
不同点:

HashMapTreeMapLinkedHashMap
按顺序插入存放不支持不支持支持,遍历时按插入的顺序输出
按Key排序不支持支持,默认按key升序不支持
数据结构数组+链表+红黑树红黑树HashMap+双向链表
nullkey,value都可以为空,但是Key只能有一个为空不允许key,value为空key,value都可以为空,但是Key只能有一个为空

HashMap为什么线程不安全?如何线程安全地操作?

安全使用Map的三种方法:
1.HashTable,在get/put方法上加上了synchronized关键字,性能很差。
2.Collections.synchronizedMap,所有的方法都加上了synchronized关键字,性能很差。
3.ConcurrentHashMap,每次只给一个桶(数组项)加锁,性能好。

HashMap线程不安全的原因:
1.数据覆盖,
2.读出为null
3.JDK1.7会出现死循环。

ConcurrentHashMap原理?

在JDK1.8后,ConcurrentHashMap采用的是HashMap(数组+链表+红黑树)+synchronized +CAS的设计来实现线程安全。
CAS:在判断数组中当前位置为null时,使用CAS把这个新的节点写入对应数组中的位置。
synchronized:当数组中当前位置不为空时,通过加锁来添加这个节点进入数组(链表<8)或者红黑树(链表>=8)

线程池有哪些参数?

1.corePoolSize:线程池的核心线程数,即便没有任务也会有这么多的线程在等候;
2.maximunPoolSize:最大线程数,超过这个数量会触发拒绝策略。
3.keepAliveTime:线程存活时间,当线程大于corePoolSize时,等到这个时间还没有任务执行的话,线程退出。
4.unit:指定keepAliveTime的单位,如TimeUnit.SECONDS 秒。
5.workQueue:阻塞队列,提交的任务会被放在这个队列里。
6.threadFactory:线程工场,用来创建线程。
7.handler:拒绝策略

ArrayList扩容机制

当我们直接new 一个ArrayList对象时(未指定大小),new 出来的是一个空数组,容量为0;
当第一次调用add 方法时,分配容量,如果是空数组,最小默认容量为10,当需求容量大于此时的容量是,执行扩容方法grow(),扩容为当前容量的1.5倍,然后比较需求容量与扩容后的容量,如果需求容量大于扩容后的容量,那么就将需求容量作为新的容量值,否则去扩容后的容量,然后再进行复制操作,将数据复制到新的数组中。

HashMap数据结构、哈希冲突解决方法?

HashMap其实就是一个大的数组,将Key的HashCode作为数组的下标,value 作为数组的值,当key的hash值冲突时,将新key和旧Key放到链表中。
链表的长度大于8且小于64,会自动扩容,当链表长度大于8且大于64,会自动转为红黑树。如果红黑树的节点数小于6,则将红黑树转为链表。
当发生hash冲突时,通过链地址法将指向下一个entry

HashMap扩容的原理?

HashMap是懒加载,再构建完对象后,没有发生put操作之前,不会初始化和扩容。
当发生首次put时,会调用resize方法进行初始化。初始化的容量为2^4;
当put发现数组大小大于阈值(当前大小的75%)时调用resize方法进行扩容;
扩容大小为当前的大小的2倍,扩容后判断新的容量是否大于最大容量,如果大于最大容量,实际大小为最大容量,最大容量为:2^30。

JVM通常设置哪些参数来调优?

-Xms 初始堆大小
-Xmx 最大堆大小
-Xss 线程栈大小
-XX:NewSize=n 设置年轻代大小
-Xmn 设置年轻代初始大小和最大大小,年轻代增大,老年代就会减小,Sun官方推荐的配置时年轻代占整个堆的3/8

GC信息

-XX:+PrintGC 打印GC日志
-XX:+PrintGCDetails 打印详细的GC日志信息
-XX:+PrintGCTimeStamps 打印进程启动到现在经历的时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值