java基础复习(第四日)

java基础复习(四)

1.说一下HashMap、LinkedHashMap、concurrentHashMap、ArrayList、LinkedList的底层实现

1、HashMap是java数据结构中两大结构数组+链表+红黑树的组合。

HashMap底层数组,数组中的每一项又是一个链表。程序会先根据key的hashcode()方法返回值决定该Entry在数组中的

存储位置,如果该位置上没有元素,就会将元素放置在此位置上,如果两个Entry的key相同,会调用equals,返回值是true则覆盖原来的value值,返回false则会形成Entry链,位于头部。

2、ArrrayList的底层实现是数组,在执行add操作时,会先检查数组 大小是否可以容纳新的元素,如果不够就会进行扩容。然后会将原来的数据拷贝到新的数组中。

3、LinkedList底层是一个双向循环链表,其实现增删改查和数据结构中的操作完全相同,而且插入是有序的。

4、LinkedHashMap的底层结构式是双向链表,其他的逻辑处理与HashMap一致,同样没有锁保护,多线程使用时存在风险。

5、ConcurrentHashMap的底层数据结构:Synchronized + CAS +Node +红黑树.Node的val和next都用volatile保证,保证可见性,查找,替换,赋值操作都使用CAS(jdk1.8版本)

2.说一下 Callable 和 Runnable 的区别?

Runnable和Callable区别是否有返回值

Runnable接口不能获取线程的返回值,所以也就无法知道线程是否执行成功,而Callable接口获取到线程的返回值(Future对象),通过返回值可以判断线程是否执行成功或取消任务

callable可以抛出异常,runnable 方法不行

3.静态变量和实例变量的区别是什么?

区别一、定义不同

  • 静态变量定义时候前面要加上static,实例变量不需要加。

区别二、初始化不同

  • 静态变量随着类的加载而初始化,实例变量是new对象后才进行初始化。

区别三、内存位置不同(JDK1.8后都存在堆中了)

  • 静态变量存储在静态变量区,实例变量存储在堆内存区

区别四、调用方式不同

  • 静态变量通过类名调用,实例变量通过对象调用

区别五、生命周期不用

  • 静态变量随着类的加载而加载,虚拟机停止运行时,静态变量周期结束。实例变量随着对象的产生

4.说一说 Redis 缓存穿透的解决方案?

了解下 缓存穿透

key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,违法分子利用漏洞进行攻击可能压垮数据库

  • 1.查缓存没有的数据 比如 id:-1 命中率降低
  • 2.导致大量请求直接访问DB(数据库)压力过大

解决方案:

  • 1.对空值缓存

    • 如果一个查询返回的数据为空(不管是数据是否不存在),我们把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
  • 2.设置可访问的名单(白名单)

    • 使用 bitmaps 类型定义一个可以访问的名称, 名单 id 作为 bitaps 的偏移量,每次访问 和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问
  • 3.采用布隆过滤器

    • 简介:(布隆过滤器(Bloom Filter)是 1970 年由布隆提出的它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希数))
    • 有缺点 1.性能占用 2.存在误判 3.删除困难
    • 最大数值非常大的时候,布隆过滤器需要的空间少的多
    • 查到元素不存在容器中,hash得到k个位置上的值都是1,可以建立白名单存储可能会误判的元素
    • 放入容器的元素映射到bit数组的k个位置上是1,删除时不能直接重置为0,可能会影响元素的判断 ,采用Counting Bloom Filter
  • 4.进行实时监控

    • 当发现 Redis 的命中率急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单

5.描述 Cookie 和 Session 的作用、区别和应用范围,Seesion 工作原理

Cookie 和 Seesion 的区别:

1.session存放在服务器,cookie存放在客户端

2.session会随着会话的结束而关闭,cookie则存放在客户端浏览器上长期有效

3.seesion 保存的是对象,cookie保存的是字符串

4.存放在cookie里的信息容易泄露,通常只保存重要的信息,重要的信息放在session中(如token)

6.ArrayList扩容时扩容多少?

在每次存入数据后会进行检查,如果超过容量最大值,则以原容量的1.5倍继续扩容

初始容量:10

扩容一次:10*1.5=15

扩容两次:(10*1.5)*1.5=22.5

7.java垃圾回收算法有哪些?

1.标记-清除算法

java堆内存中的对象实例是动态分配和回收的,java虚拟机提供了多种不同的内存回收算法来满足不同的内存管理需求

标记-清除算法是最基础的内存回收算法

主要流程:

  • 标记所有活跃对象
  • 清除所有未被标记的对象

缺点:会产生内存碎片,导致内存利用率降低

2.复制算法

复制算法是将内存分为两部分,每次只使用其中一部分。当这部分内存用完后,将其中的活跃对象复制到另一部分中,然后清除这部分内存

复制算法的优点是可以避免内存碎片,缺点是需要消耗额外的内存空间

复制算法主要用于新生代内存回收

3.标记-整理算法

标记-整理算法是将内存分为两部分,一部分存储活跃对象,另一部分为未使用的内存空间。当内存空间不足时,先进行标记活跃对象,然后将活跃对象整理到未使用的内存空间中,最后清除未使用的内存空间

标记-整理算法可以避免内存碎片,但其缺点是需要移动内存中的对象,因此效率较低

标记-整理算法主要用于老年代内存回收

4.分代回收算法

分代回收算法是根据对象的生命周期将内存分为不同的代,每个代使用不同的内存回收算法。

新生代中一般使用复制算法,由于新生代中大部分对象的生命周期很短,因此这种算法的效率较高。而老年代中一般使用标记-整理算法,由于老年代中存储的对象生命周期较长,因此算法能够有效地减少垃圾回收的次数,提高Java应用的性能

5.G1算法

G1算法是一种面向服务端应用的垃圾回收算法。它将堆内存划分为多个大小相等的区域(Region),每个区域既可以是新生代也可以是老年代。G1算法会根据应用程序的内存使用情况动态地调整各个区域的大小

在G1算法中,垃圾回收器不再按照新生代和老年代的划分进行垃圾回收,而是将整个堆空间一起考虑。G1算法使用了类似分代回收算法的思想,将堆空间分为多个区域,每个区域的回收策略可以不同,这样就能够更加灵活地进行内存回收

G1算法的优点是能够在保证垃圾回收效率的同时,避免了内存碎片的问题。同时,由于G1算法能够动态调整各个区域的大小,因此可以更好地适应不同的应用场景

8.JDK和JRE 有什么区别?

JDK是java开发工具包,里面包含了编译器、调试器和其他工具

提供了java开发环境和运行环境(JDK中也包含JRE,因为编写好的程序也要测试运行)

JRE是运行环境,里面包含jvm(Java虚拟机)和基础类库

9.Redis 缓存和 JVM 缓存有什么区别?

jvm缓存,

  • 会有回收问题
  • 每次启动时都需要灌入数据

redis缓存

  • 有内存淘汰策略(8种)
  • 通过RDB快照 快速加载
  • redis和本地缓存之间还有堆外缓存

这三种缓存可以实现出一个多级缓存架构

10.为什么 Redis 使用单线程性能会优于多线程?

Redis 是单线程 + 多路 IO 复用技术

  • 避免上下午切换和竞争条件
  • 也不存在多线程切换而消耗cpu
  • 不存在锁问题

你可能感兴趣的:(面试题,Java面试,java,开发语言)