Java面试题

** 1.ArrayList和LinkedList的区别**

List是有序的、可重复的集合。
ArrayList基于数组的线性表,LinkedList基于链的线性表。
LinkedList:有List的功能+双端队列+栈的功能。

  • ArrayList 比LinkedList性能好:
    ArrayList:基于数组的线性表,因为数组以一块连续内存区来保存所有的数组元素,所以数组在随机访问时性能最好。
    LinkedList:基于链表的线性表,在执行插入、删除操作时性能好。

2. HashMap的具体模型,为什么链表长度到8,才扩展为红黑树
原因:
为什么要转换?
因为Map中桶的元素初始化是链表保存的,其查找性能是O(n),而树结构能将查找性能提升到O(log(n))。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。

为什么阈值是8?
转换后存储的数据结构TreeNodes占用空间是普通Nodes的两倍,只有当bin包含足够多的节点时才会转成TreeNodes,而是否足够多是由TREEIFY_THRESHOLD的值决定的。

在hashCode离散性很好的情况下,树型bin(桶,即bucket,HashMap中hashCode值一样的元素保存的地方)用到的概率非常小,因为数据均匀分布在每个bin中,几乎不会有bin中链表长度会达到阈值。事实上,在随机hashCode的情况下,在bin中节点的分布频率遵循如下的泊松分布(http://en.wikipedia.org/wiki/Poisson_distribution)。

在扩容阈值为0.75的情况下,(即使因为扩容而方差很大)遵循着参数平均为0.5的泊松分布。忽略方差,按公式
在这里插入图片描述
如上,一个bin中链表长度达到8个元素的概率为0.00000006,几乎是不可能事件。

大部分情况下,链表存储能节约存储空间同时有着良好的查找性能极个别情况下,节点数达到8个,转为红黑树,能获得更好的查找性能,同时因为是个别情况不需要大量的存储空间。

长度<=6,选择链表
长度>=8,选择红黑树

还有选择6和8的原因是:

中间有个差值7可以防止链表和树之间频繁的转换

3.synchronized,ConcurrentHashMap的实现
synchronized同步代码块(共享资源是同步监视器),同步方法(调用该方法的this是同步监视器)。
ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现。
 HashMap :先说HashMap,HashMap是线程不安全的,在并发环境下,可能会形成环状链表(扩容时可能造成,具体原因自行百度google或查看源码分析),导致get操作时,cpu空转,所以,在并发环境中使用HashMap是非常危险的。

HashTable : HashTable和HashMap的实现原理几乎一样,差别无非是1.HashTable不允许key和value为null ; ** 2.HashTable是线程安全的。但是HashTable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差**。
  在这里插入图片描述
  HashTable性能差主要是由于所有操作需要竞争同一把锁,而如果容器中有多把锁,每一把锁锁一段数据,这样在多线程访问时不同段的数据时,就不会存在锁竞争了,这样便可以有效地提高并发效率。这就是ConcurrentHashMap所采用的**“分段锁”**思想。
  在这里插入图片描述ConcurrentHashMap源码分析
  ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组。
   final Segment<K,V>[] segments;
  Segment继承了ReentrantLock,所以它就是一种可重入锁(ReentrantLock)。在ConcurrentHashMap,一个Segment就是一个子哈希表,Segment里维护了一个HashEntry数组,并发环境下,对于不同Segment的数据进行操作是不用考虑锁竞争的。(就按默认的ConcurrentLeve为16来讲,理论上就允许16个线程并发执行,有木有很酷)

所以,对于同一个Segment的操作才需考虑线程同步,不同的Segment则无需考虑。

Segment类似于HashMap,一个Segment维护着一个HashEntry数组
一个ConcurrentHashMap维护一个Segment数组,一个Segment维护一个HashEntry数组。

4. 聚集索引,非聚集索引,索引匹配,int(10)的含义,mysql常用数据类型
聚集(clustered)索引,也叫聚簇索引。
定义:数据行的物理顺序列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。
在这里插入图片描述
非聚集索引:
该索引中索引的逻辑顺序磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。
非聚集索引就像新华字典的偏旁字典,他结构顺序与实际存放顺序不一定一致。

  • 使用聚集索引的查询效率要比非聚集索引的效率要高,但是如果需要频繁去改变聚集索引的值,写入性能并不高,因为需要移动对应数据的物理位置。
  • 非聚集索引在查询的时候可以的话就避免二次查询,这样性能会大幅提升。
  • 不是所有的表都适合建立索引,只有数据量大表才适合建立索引,且建立在选择性高的列上面性能会更好。

int(10)表示的是数据显示的长度为10位。
MySQL支持多种类型,大致可以分为三类:数值日期/时间字符串(字符)类型。
5. linux常用指令,查看当前运行进程命令,查找文件内容
ps -A:显示所有进程信息
linux查找文件命令find

6. jvm内存结构

一、java代码编译执行过程

1.源码编译:通过Java源码编译器将Java代码编译成JVM字节码(.class文件)
  2.类加载:通过ClassLoader及其子类来完成JVM的类加载
  3.类执行:字节码被装入内存,进入JVM虚拟机,被解释器解释执行

二、JVM简介

1.java程序经过一次编译之后,将java代码编译为字节码也就是class文件,然后在不同的操作系统上依靠不同的java虚拟机进行解释,最后再转换为不同平台的机器码,最终得到执行
2.Java虚拟机(JVM) 处在核心的位置,是程序与底层操作系统、硬件无关的关键。
   JVM的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统, 其中依赖于平台的部分称为适配器,JVM 通过移植接口在具体的平台和操作系统上实现
   JVM 的上方是Java的基本类库和扩展类库以及它们的API, 利用Java API编写的应用程序(application) 和小程序(Java applet) 可以在任何Java平台上运行而无需考虑底层平台
   Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的跨平台
   在这里插入图片描述
三、JVM内存结构:
在这里插入图片描述
1.程序计数器 PC Register
每个线程都有一个程序计算器,就是一个指针,指向方法区中的方法字节码(下一个将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。
2.本地方法栈 Native Method Stack
  Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies
  本地方法栈与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务
3.方法区 Method Area
  用于存储虚拟机加载的:静态变量+常量+类信息+运行时常量池 (类信息:类的版本、字段、方法、接口、构造函数等描述信息 )
4.栈 JVM Stack
   编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并非对象本身)
  栈是java 方法执行的内存模型:
  每个方法被执行的时候 都会创建一个“栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。
  每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
  栈的生命期是跟随线程的生命期,线程创建时创建,线程结束栈内存也就释放,是线程私有的。

5.堆 Java Heap
  所有的对象实例以及数组都要在堆上分配,此内存区域的唯一目的就是存放对象实例
  堆是Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建
  堆是理解Java GC机制最重要的区域,没有之一
  结构:新生代(Eden区+2个Survivor区) 老年代 永久代(HotSpot有)
  新生代:新创建的对象——>Eden区
  GC之后,存活的对象由Eden区 Survivor区0进入Survivor区1
  再次GC,存活的对象由Eden区 Survivor区1进入Survivor区0
  老年代:对象如果在新生代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到老年代

如果新创建对象比较大(比如长字符串或大数组),新生代空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)

老年代的空间一般比新生代大,能存放更多的对象,在老年代上发生的GC次数也比年轻代少

永久代:可以简单理解为方法区(本质上两者并不等价)
7. http状态码
200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
302:跳转,重定向
400:客户端有语法错误
403:服务器拒绝提供服务
404:请求资源不存在
500 - 内部服务器错误
在这里插入图片描述
8. tcp四次挥手,第四次挥手时一直丢包了怎么办

9. 垃圾回收机制

10. 链表倒数第n个结点

11. 线程池几种类型,有什么重要参数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值