栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java面试题2022

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java面试题2022

1、Spring AOP 底层原理

aop底层采用动态代理的机制实现:

如果要代理的对象实现了某个接口,那么会用JDK代理;如果没有实现接口,那么会用Cglib代理。

由代理类创建出一个和实现类平级的对象(代理对象),它可以实现和原有实现类相同的功能,这个就是aop的横向机制原理,这样就不需要修改源代码。

2、HashMap的底层数据结构是怎样的?

JDK1.8以前

JDK1.8以前HashMap底层是数组+链表结合的方式来实现的;HashMap通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n -1) & hash来得到存放于数组中的下标位置,如果当前位置存在元素,则判断Hash值和key是否相同,如果相同直接覆盖,不相同就用拉链法来解决冲突;所谓扰动函数就是HashMap的Hash方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。

JDK1.8以后

当链表长度大于阈值( 默认为 8) 时, 会首先调用 treeifyBin()方法。 这个方法会根据HashMap 数组来决定是否转换为红黑树。 只有当数组长度大于或者等于 64 的情况下, 才会执行转换红黑树操作, 以减少搜索时间。 否则, 就是只是执行 resize() 方法对数组扩容。 3、HashMap的扩容机制

一般情况下, 当元素数量超过阈值时便会触发扩容。 每次扩容的容量都是之前容量的 2 倍。
HashMap 的容量是有上限的, 必须小于 1<<30, 即 1073741824。 如果容量超出了这个
数, 则不再增长, 且阈值会被设置为 Integer.MAX_VALUE。


JDK1.7中的扩容机制:

实例化的 HashMap 默认内部数组是 null, 即没有实例化。 第一次调用 put 方法时, 则会开始第一次初始化扩容, 长度为 16;平衡因子为0.75,默认阈值为16*0.75=12,大于阈值时候会扩容;如果不是第一次扩容, 则 新容量=旧容量 x 2 , 新阈值=新容量 x 负载因子 。

JDK1.8中的扩容机制:

如果不是第一次扩容, 则容量变为原来的 2 倍, 阈值也变为原来的 2 倍。 ( 容量和阈值都变为原来的 2 倍时, 负载因子还是不变) ;链表长度大于8时才会转换为红黑树,红黑树长度小于6时会退化为链表; 4、 ConcurrentHashMap 的存储结构是怎样的?

Java7 中 ConcurrnetHashMap 使用的分段锁, 也就是每一个 Segment 上同时只有一
个线程可以操作, 每一个 Segment 都是一个类似 HashMap 数组的结构, 它可以扩容,
它的冲突会转化为链表。 但是 Segment 的个数一但初始化就不能改变, 默认 Segment
的个数是 16 个。

Java8 中的 ConcurrnetHashMap 使用的 Synchronized 锁加 CAS 的机制。 结构也由
Java7 中的 Segment 数组 + HashEntry 数组 + 链表 进化成了 Node 数组 + 链表 / 红
黑树, Node 是类似于一个 HashEntry 的结构。 它的冲突再达到一定大小时会转化成红
黑树, 在冲突小于一定数量时又退回链表。

5、线程池大小如何设置?

CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源, 可以将线程数设置为 N
( CPU 核心数) +1, 比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,
或者其它原因导致的任务暂停而带来的影响。 一旦任务暂停, CPU 就会处于空闲状态,
而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。

I/O 密集型任务(2N): 这种任务应用起来, 系统会用大部分的时间来处理 I/O 交互, 而线
程在处理 I/O 的时间段内不会占用 CPU 来处理, 这时就可以将 CPU 交出给其它线程使
用。 因此在 I/O 密集型任务的应用中, 我们可以多配置一些线程, 具体的计算方法是 2N。

如何判断是 CPU 密集任务还是 IO 密集任务?
CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。
单凡涉及到网络读取, 文件读取这类都是 IO 密集型, 这类任务的特点是 CPU 计算耗费时间
相比于等待 IO 操作完成的时间来说很少, 大部分时间都花在了等待 IO 操作完成上。

6、 你有哪些手段来排查 OOM 的问题?

 增加两个参数 -XX:+HeapDumponOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof, 当 OOM 发生时自动 dump 堆内存信息到指定目录。 同时 jstat 查看监控 JVM 的内存和 GC 情况, 先观察问题大概出在什么区域。 使用 MAT 工具载入到 dump 文件, 分析大对象的占用情况, 比如 HashMap 做缓存未清理, 时间长了就会内存溢出, 可以把改为弱引用。 7、请你谈谈 MySQL 事务隔离级别, MySQL 的默认隔离级别是什么?

为了达到事务的四大特性, 数据库定义了 4 种不同的事务隔离级别:

READ-UNCOMMITTED( 读取未提交) : 最低的隔离级别, 允许脏读, 也就是可能读取到其他会话中未提交事务修改的数据, 可能会导致脏读、 幻读或不可重复读。READ-COMMITTED( 读取已提交) : 只能读取到已经提交的数据。 Oracle 等多数数据库默认都是该级别 ( 不重复读) , 可以阻止脏读, 但是幻读或不可重复读仍有可能发生。 REPEATABLE-READ( 可重复读) : 对同一字段的多次读取结果都是一致的, 除非数据是被本身事务自己所修改, 可以阻止脏读和不可重复读, 但幻读仍有可能发生。 SERIALIZABLE( 可串行化) : 最高的隔离级别, 完全服从 ACID 的隔离级别。 所有的事务依次逐个执行, 这样事务之间就完全不可能产生干扰, 也就是说, 该级别可以防止脏读、 不可重复读以及幻读。 MySQL 默认采用的 REPEATABLE_READ 隔离级别。可重复读的核心是在一个事务内多次读取同一个数据,得到的内容都是一致的。 8、对 SQL 慢查询会考虑哪些优化 ?

分析语句, 是否加载了不必要的字段/数据分析 SQL 执行计划( explain extended) , 思考可能的优化点, 是否命中索引等;查看 SQL 涉及的表结构和索引信息,如果 SQL 很复杂, 优化 SQL 结构;按照可能的优化点执行表结构变更、 增加索引、 SQL 改写等操作。查看优化后的执行时间和执行计划。如果表数据量太大, 考虑分表。利用缓存, 减少查询次数。 9、谈一谈缓存穿透、 缓存击穿和缓存雪崩, 以及解决办法?

缓存穿透

问题: 大量并发查询不存在的 KEY, 在缓存和数据库中都不存在, 同时给缓存和数据库带来压力。原因: 一般而言, 缓存穿透有 2 种可能性: 业务数据被误删, 导致缓存和数据库中都没有数据。 恶意进行 ddos 攻击。解决办法:缓存空值的 KEY, 这样第一次不存在也会被加载会记录, 下次拿到有这个KEY。Bloom 过滤或 RoaingBitmap 判断 KEY 是否存在, 如果布隆过滤器中没有查到这个数据, 就不去数据库中查。在处理请求前增加恶意请求检查, 如果检测到是恶意攻击,则拒绝进行服务。完全以缓存为准, 使用延迟异步加载的策略( 异步线程负责维护缓存的数据, 定期或根据条件触发更新) , 这样就不会触发更新。

缓存击穿

问题: 某个 KEY 失效的时候, 正好有大量并发请求访问这个 KEY。分析: 跟穿透其实很像, 属于比较偶然的。解决办法:KEY 的更新操作添加全局互斥锁。完全以缓存为准, 使用延迟异步加载的策略( 异步线程负责维护缓存的数据, 定期或根据条件触发更新) , 这样就不会触发更新。

缓存雪崩

问题: 当某一时刻发生大规模的缓存失效的情况, 导致大量的请求无法获取数据, 从而将流量压力传导到数据库上, 导致数据库压力过大甚至宕机。原因: 一般而言, 缓存雪崩有 2 种可能性: 大量的数据同一个时间失效: 比如业务关系强相关的数据要求同时失效 Redis 宕机分析: 一般来说, 由于更新策略、 或者数据热点、 缓存服务宕机等原因, 可能会导致缓存数据同一个时间点大规模不可用, 或者都更新。 所以, 需要我们的更新策略要在时间上合适, 数据要均匀分享, 缓存服务器要多台高可用。解决办法:更新策略在时间上做到比较平均。 如果数据需要同一时间失效, 可以给这批数据加上一些随机值, 使得这批数据不要在同一个时间过期, 降低数据库的压力。使用的热数据尽量分散到不同的机器上。 多台机器做主从复制或者多副本, 实现高可用。 做好主从的部署, 当主节点挂掉后, 能快速的使用从结点顶上。实现熔断限流机制, 对系统进行负载能力控制。 对于非核心功能的业务, 拒绝其请求, 只允许核心功能业务访问数据库获取数据。服务降价: 提供默认返回值, 或简单的提示信息。 10、MySQL 索引底层结构为什么使用 B+树?

哈希虽然能够提供 O(1) 的单数据行操作性能, 但是对于范围查询和排序却无法很好地支持, 最终导致全表扫描;B 树能够在非叶节子点中存储数据, 但是这也导致在查询连续数据时可能会带来更多的随机 I/O;而 B+树的所有叶节点可以通过指针相互连接, 能够减少顺序遍历时产生的额外随机 I/O;B 树一个节点里存的是数据, 而 B+树存储的是索引( 地址) , 所以 B 树里一个节点存不了很多个数据, 但是 B+树一个节点能存很多索引, B+树叶子节点存所有的数据。B+树的高度比B树高低,查询时间复杂度要低;B+树的叶子节点是数据阶段用了一个链表(双向链表)串联起来, 便于范围查找。 11、索引失效的情况有哪些

like 以%开头索引无效, 当 like 以&结尾, 索引有效;在索引列上使用 IS NULL 或者 IS NOT NULL 时候, 索引失效, 因为索引是不索引空值得组合索引, 使用的不是第一列索引时候, 索引失效, 即最左匹配规则在索引字段上使用, NOT、 <>、 ! = 、 时候是不会使用索引的, 对于这样的处理只会进行全表扫描。or 语句前后没有同事使用索引, 当且仅当 or 语句查询条件的前后列均为索引时, 索引生效。对索引字段进行计算操作, 函数操作时不会使用索引。数据类型出现隐式转换, 如 varchar 不加单引号的时候可能会自动转换为 int 类型, 这个时候索引失效。当全表扫描速度比索引速度快的时候不会使用索引。 12、Redis9种基本数据结构以及8种内部编码

string:最基本的数据类型,二进制安全的字符串,最大512M。

应用:缓存,热点数据分布式session分布式锁文章的阅读量,微博点赞数,允许一定的延迟,先写入 Redis 再定时同步到数据库全局ID内部编码:int:8 个字节的长整型(long,2^63-1)embstr:小于等于44个字节的字符串,embstr格式的SDS(Simple Dynamic String)raw:SDS大于 44 个字节的字符串list:按照添加顺序保持顺序的字符串列表(双向列表)。

应用:关注列表、粉丝列表

消息队列

内部编码:

zipList

linkList

set:无序的字符串集合,不存在重复的元素。set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的。

应用:知乎点赞共同关注人、可能认识的人(多个 set 取交集、并集、差集)商城商品筛选内部编码:intset(整数集合):当集合中的元素都是整数,并且集合中的元素个数小于 512 个时,Redis 会选用 intset 作为底层内部实现。hashtable(哈希表):当上述条件不满足时,Redis 会采用 hashtable 作为底层实现。sorted set:已排序的字符串集合。

内部编码:

ziplist(压缩列表)skiplist(跳跃表)
 hash:key-value对的一种集合。

应用:对象数据,用户 ID 为查找的 key,存储的 value 用户对象包含姓名,年龄,生日等信息。购物车内部编码:ziplist(压缩列表):当哈希类型中元素个数小于 hash-max-ziplist-entries 配置(默认 512 个),同时所有值都小于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使用 ziplist 作为哈希的内部实现。hashtable(哈希表):当上述条件不满足时,Redis 则会采用 hashtable 作为哈希的内部实现。
 bitmap:更细化的一种操作,以bit为单位。有一些数据只有两个属性,比如是否是学生,是否是党员等等,对于这些数据,最节约内存的方式就是用bit去记录,以是否是学生为例,1代表是学生,0代表不是学生

应用:在线状态签到状态hyperloglog:基于概率的数据结构,Redis 的基数统计,这个结构可以非常省内存的去统计各种计数。 它在 Redis 的内部结构表现就是一个字符串位图。你可以把 HyperLogLog 对象当成普通的字符串来进行处理。# 2.8.9新增

应用:注册 IP 数、每日访问 IP 数、页面实时UV)、在线用户数Geo:地理位置信息储存起来, 并对这些信息进行操作   # 3.2新增

内部编码:Geo本身不是一种数据结构,它本质上还是借助于Sorted Set应用场景:

比如现在比较火的直播业务,我们需要检索附近的主播,那么GEO就可以很好的实现这个功能。

一是主播开播的时候写入主播Id的经纬度,二是主播关播的时候删除主播Id元素,这样就维护了一个具有位置信息的在线主播集合提供给线上检索。流(Stream):用一句话概括Streams就是Redis实现的内存版kafka。支持多播的可持久化的消息队列,用于实现发布订阅功能,借鉴了 kafka 的设计。# 5.0新增

内部编码:streams底层的数据结构是radix tree:Radix Tree(基数树) 事实上就几乎相同是传统的二叉树  13、 Redis 主从同步是怎么实现的

主从刚刚连接的时候, 进行全量同步; 全同步结束后, 进行增量同步。 当然, 如果有需要,
slave 在任何时候都可以发起全量同步。 redis 策略是, 无论如何, 首先会尝试进行增量同步,
如不成功, 要求从机进行全量同步。
 

14、Redis 持久化 RDB 和 AOF 优缺点

RDB:

RDB 持久化方式, 是将 Redis 某一时刻的数据持久化到磁盘中, 是一种快照式的持久化方

优点:

RDB 作为一个非常紧凑( 有压缩) 的文件, 可以很方便传送到另一个远端数据中心 , 非常适用于灾难恢复。RDB 在保存 RDB 文件时父进程唯一需要做的就是 fork 出一个子进程,接下来的工作全部由子进程来做, 父进程不需要再做其他 IO 操作, 所以 RDB 持久化方式可以最大化redis 的性能。与 AOF 相比, 在恢复大的数据集的时候, RDB 方式会更快一些

缺点:

Redis 意外宕机时, 会丢失部分数据。当 Redis 数据量比较大时, fork 的过程是非常耗时的, fork 子进程时是会阻塞的, 在这期间 Redis 是不能响应客户端的请求的

AOF:

AOF 方式是将执行过的写指令记录下来, 在数据恢复时按照从前到后的顺序再将指令都执行
一遍。
优点:

持久化效率更高,AOF 文件可读性高, 分析容易

缺点:

对于相同的数据来说, AOF 文件大小通常要大于 RDB 文件。AOF恢复数据的速度可能会慢于 RDB。 15、SpringAOP的理解

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关, 却为业务模块
所共同调用的逻辑或责任( 例如事务处理、 日志管理、 权限控制等) 封装起来, 便于减少系统
的重复代码, 降低模块间的耦合度, 并有利于未来的可拓展性和可维护性
 

16、Spring Bean 容器的生命周期是什么样的?

Bean 容器找到配置文件中 Spring Bean 的定义。Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。如果涉及到一些属性值 利用 set()方法设置一些属性值。如果 Bean 实现了 BeanNameAware 接口, 调用 setBeanName()方法, 传入 Bean 的名字。如果 Bean 在配置文件中的定义包含 init-method 属性, 执行指定的方法。当要销毁 Bean 的时候, 如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。 17、RabbitMQ 如何保证消息不丢失

生产者: 开启 confirm 模式(异步, 性能较好)MQ: (1)exchange 持久化 (2)queue 持久化 (3)消息持久化消费者: 关闭自动 应答(ACK),使用手动应答 18、TCP 和 UDP 区别

UDP报文头结构简单,需要的资源少,主要用于直播、游戏等对数据实时性的要求比较高的传输;TCP 报文头里面的序号能使 TCP 的数据按序到达报文头里面的确认序号能保证不丢包,累计确认及超时重传机制TCP 拥有流量控制及拥塞控制的机制TCP 的顺序问题,丢包问题,流量控制都是通过滑动窗口来解决的
拥塞控制时通过拥塞窗口来解决的TCP 基于连接,有三次握手三次挥手, UDP 基于无连接。TCP 要求系统资源较多, UDP 较少。UDP 程序结构较简单。TCP 保证数据正确性, UDP 可能丢包。TCP 保证数据顺序, UDP 不保证。

4次挥手:

TCP 是全双工, 每个方向都必须进行单独关闭。关闭连接时, 当 Server 端收到 关闭连接的
报文时, 很可能并不会立即关闭 SOCKET, 所以只能先回复一个 ACK 报文, 告诉 Client
端, ” 你发的 FIN 报文我收到了” 。 只有等到 Server 端所有的报文都发送完了, 我才能发
送 FIN 报文, 因此不能一起发送。 故需要四步握手
  19、线程池主要参数

高并发,大任务时候需要用到多线程。大任务处理起来比较耗时, 这时候可以起到多个线程并行加快处理( 例如: 分片上传) 。 可以提高 CPU 的利用率

 corePoolSize : 核心线程数线程数定义了最小可以同时运行的线程数量。 maximumPoolSize : 当队列中存放的任务达到队列容量的时候, 当前可以同时运行的线程数量变为最大线程数。workQueue: 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数, 如果达到的话, 信任就会被存放在队列中如果当前线程数=corePoolSize, 则将任务存入 BlockingQueue 。如果阻塞队列已满, 且当前线程数=maximumPoolSize, 则抛出异常 。 20、描述 ThreadLocal( 线程本地变量) 的底层实现原理及常用场景

hreadLocal 是一个解决线程并发问题的一个类, 用于创建线程的本地变量, 我们知道一个
对象的所有线程会共享它的全局变量, 所以这些变量不是线程安全的, 我们可以使用同步技术。
但是当我们不想使用同步的时候, 我们可以选择 ThreadLocal 变量。 例如, 由于 JDBC 的
连接对象不是线程安全的, 因此, 当多线程应用程序在没有协同的情况下, 使用全局变量时,
就不是线程安全的。 通过将 JDBC 的连接对象保存到 ThreadLocal 中, 每个线程都会拥有
属于自己的连接对象副本。


21、MySQL 事务的特性有什么, 说一下分别是什么意思?

原子性: 即不可分割性, 事务要么全部被执行, 要么就全部不被执行。隔离性:同一时间,只允许一个事务请求同一组数据。不同的事务彼此之间没有干扰。一致性:事务开始前和结束后,数据库的完整性约束没有被破坏。持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失 22、哪些情况下的对象会被垃圾回收机制处理掉?

利用可达性分析算法, 虚拟机会将一些对象定义为 GCRoots, 从 GCRoots 出发沿着引用链
向下寻找, 如果某个对象不能通过 GCRoots 寻找到, 虚拟机就认为该对象可以被回收掉。
 哪些对象可以被看做是 GCRoots 呢?
1) 虚拟机栈( 栈帧中的本地变量表) 中引用的对象;
2) 方法区中的类静态属性引用的对象, 常量引用的对象;
3) 本地方法栈中 JNI(Native 方法) 引用的对象;

23、静态代理和动态代理的区别, 什么场景使用

代理是一种常用的设计模式, 目的是: 为其他对象提供一个代理以控制对某个对象的访问,
将两个类的关系解耦。 代理类和委托类都要实现相同的接口, 因为代理真正调用的是委托类
的方法。
区别:
静态代理: 由程序员创建或是由特定工具生成, 在代码编译时就确定了被代理的类是哪 一
个是静态代理。 静态代理通常只代理一个类;
动态代理: 在代码运行期间, 运用反射机制动态创建生成。 动态代理代理的是一个接口 下
的多个实现类;


23、反射

开发过程中, 经常会遇到某个类的某个成员变量、 方法或属性是私有的, 或只
对系统应用开放, 这里就可以利用 java 的反射机制通过反射来获取所需的私有成员或是方法。

Class.forName("com.zhenai.api.Apple");使用 Constructor 对 象 的 newInstance 方 法 获 取 反 射 类 对 象 24、注解

注解的作用:
 提供信息给编译器: 编译器可利用注解来探测错误和警告信息
 编译阶段: 软件工具可以利用注解信息来生成代码、 html 文档或做其它相应处理;
 运行阶段: 程序运行时可利用注解提取代码
注解是通过反射获取的, 可以通过 Class 对象的 isAnnotationPresent()方法判断它是否应
用了某个注解, 再通过 getAnnotation()方法获取 Annotation 对象


25、 String 为什么要设计成不可变的?

因为 String 设计成不可变, 当创建一个 String 对象时, 若此字符串值已经存在于常量池中, 则不会创建一个新的对象, 而是引用已经存在的
对象。
String 对象可以缓存 hashCode。 字符串的不可变性保证了 hash 码的唯一性, 因此可
以缓 存 String 的 hashCode, 这样不用每次去重新计算哈希码。 在进行字符串比较时,
可以直接比较 hashCode, 提高了比较性能;


26、 Java 怎么实现线程安全?

使用同步代码块使用同步方法使用 Lock 锁机制, 通过创建 Lock 对象, 采用 lock()加锁, unlock()解锁, 来保护指定的代码块 27、介绍下 Spring Bean 都有哪些作用域

单例 singleton : bean 在每个 Spring IOC 容器中只有一个实例。原型 prototype: 一个 bean 的定义可以有多个实例。request: 每次 http 请求都会创建一个 bean。session: 在一个 HTTP Session 中, 一个 bean 定义对应一个实例 28、注解 @Autowired 和 @Resource 有什么区别

Resource 是 JDK 提供的, 而 Autowired 是 Spring 提供的@Autowired 默认按类型装配, 默认情况下必须要求依赖对象存在, 如果要允许 null值, 可以设置它的 required 属性为 false。 如果想使用名称装配可以结合@Qualifier 注解进行使用。@Resource, 默认按照名称进行装配, 名称可以通过 name 属性进行指定, 如果没指定 name 属性, 当注解写在字段上时, 默认取字段名进行名称查找。如果注解写在 setter方法上默认取属性名进行装配。 当找不到与名称匹配的 bean 时才按照类型进行装配。 29、MySQL 索引分类?

单列索引

普通索引: MySQL 中基本索引类型, 没有什么限制, 允许在定义索引的列中插入重复值和空值, 纯粹为了查询数据更快一点。唯一索引: 索引列中的值必须是唯一的, 但是允许为空值,主键索引: 是一种特殊的唯一索引, 不允许有空值组合索引:

多个字段组合上创建的索引, 只有在查询条件中使用了这些字段的左边字段时, 索引才会被使用, 使用组合索引时遵循最左前缀集合。全文索引:

只有在 MyISAM 引擎上才能使用, 只能在 CHAR,VARCHAR,TEXT 类型字段上使用全文索引, 介绍了要求, 说说什么是全文索引, 就是在一堆文字中, 通过其中的某个关键字等, 就能找到该字段所属的记录行, 比如有"你是个靓仔, 靓女 ..." 通过靓仔, 可能就可以找到该条记录空间索引:

空间索引是对空间数据类型的字段建立的索引, MySQL 中的空间数据类型有四种,GEOMETRY、 POINT、 LINESTRING、 POLYGON。 在创建空间索引时, 使用 SPATIAL 关键字。 要求, 引擎为 MyISAM, 创建空间索引的列, 必须将其声明为 NOT NULL。 30、线程 & 进程的区别

线程作为调度和分配的基本单位,进程作为拥有资源的基本单位一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。进程拥有自己的内存空间。 线程使用进程的内存空间, 且要和该进程的其他线程共享这个空间; 而不是在进程中给每个线程单独划分一点空间。( 同一进程中的) 线程在共享内存空间中运行, 而进程在不同的内存空间中运行 线程可以控制同一进程的其他线程。 进程无法控制兄弟进程, 只能控制其子进程线程可以使用 wait( ) , notify( ) , notifyAll( ) 等方法直接与其他线程( 同一进程)通信; 而, 进程需要使用“ 进程间通信” ( IPC) 来与操作系统中的其他进程通信。进程之间通过管道(pipe)、信号量(semophore)、套接字(socket)等方式通信 31、分布式锁

基于数据库实现分布式锁基于缓存实现分布式锁基于 Zookeeper 实现分布式锁Redis 分布式锁实现: 先拿 setnx 来争抢锁, 抢到之后, 再用 expire(过期)给锁加一个
过期时间防止锁忘记了释放。setnx 和 expire 合成一条指令来用的! 32、ArrayList 和 linkedList 的区别在哪里?

数据结构实现: ArrayList : 基于数组, 便于按 index 访问, 超过数组需要扩容, 扩容成本较高。 linkedList: 使用链表实现, 无需扩容。随机访问效率: ArrayList 比 linkedList 在随机访问的时候效率要高, 因为 linkedList是线性的数据存储方式, 所以需要移动指针从前往后依次查找。增加和删除效率: 在非首尾的增删操作, linkedList 要比 ArrayList 效率要高, 因为ArrayList 增删操作要影响数组内的其他数据的下标。内存空间占用: linkedList 比 ArrayList 更占内存, 因为 linkedList 的节点除了存储数据, 还存储了两个引用, 一个指向前一个元素, 一个指向后一个元素。线程安全: ArrayList 和 linkList 都是不同步的, 不保证线程安全。
  33、当你用浏览器打开一个链接的时候, 计算机做了哪些工作步骤?

域名解析– > 发起 TCP 的 3 次握手 – > 建立 TCP 连接后发起 http 请求 – > 服务器响应
http 请求– >浏览器得到 html 代码 – > 浏览器解析 html 代码, 并请求 html 代码中的资
源( 如 js、 css、 图片等) – > 浏览器对页面进行渲染呈现给用户 。

34、请描述线程的生命周期, 它们之间如何切换

线程的生命周期包含 5 个阶段, 包括: 新建、 就绪、 运行、 阻塞、 销毁新建( NEW) : 就是刚使用 new 方法, new 出来的线程;
 就绪( RUNNABLE) : 就是调用的线程的 start()方法后, 这时候线程处于等待 CPU 分
配资源阶段, 谁先抢的 CPU 资源, 谁开始执行;
 运行( RUNNING) : 当就绪的线程被调度并获得 CPU 资源时, 便进入运行状态, run
方法定义了线程的操作和功能;
 阻塞( BLOCKED) : 在运行状态的时候, 可能因为某些原因导致运行状态的线程变成了
阻塞状态, 比如 sleep()、 wait()之后线程就处于了阻塞状态, 这个时候需要其他机制将
处于阻塞状态的线程唤醒, 比如调用 notify 或者 notifyAll()方法。 唤醒的线程不会立刻
执行 run 方法, 它们要再次等待 CPU 分配资源进入运行状态;
 Waiting( 无限等待) : 一个线程在等待另一个线程执行一个( 唤醒) 动作时, 该线程进
入 Waiting 状态。 进入这个状态后不能自动唤醒, 必须等待另一个线程调用 notify 方法
或者 notifyAll 方法时才能够被唤醒。
 销毁( TERMINATED) : 如果线程正常执行完毕后或线程被提前强制性的终止或出现异
常导致结束, 那么线程就要被销毁, 释放资源;
 

35、什么情况线程会进入 WAITING 状态?

调用 Object 对象的 wait 方法, 但没有指定超时值。调用 Thread 对象的 join 方法, 但没有指定超时值。调用 LockSupport 对象的 park 方法 36、limit 1000000 加载很慢的话, 你是怎么解决的呢?

方案一: 如果 id 是连续的, 可以这样, 返回上次查询的最大记录(偏移量), 再往下 limit
select id, name from employee where id>1000000 limit 10.
方案二: 在业务允许的情况下限制页数:
建议跟业务讨论, 有没有必要查这么后的分页啦。 因为绝大多数用户都不会往后翻太多页。
方案三: order by + 索引( id 为索引)
select id, name from employee order by id limit 1000000, 10
方案四: 利用延迟关联或者子查询优化超多分页场景。 ( 先快速定位需要获取的 id 段, 然后
再关联)
SELECt a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b
where a.id=b.id
 

37、MySQL 的主从复制了解吗

主库将变更写入 binlog 日志, 然后从库连接到主库之后, 从库有一个 IO 线程, 将主库的
binlog 日志拷贝到自己本地, 写入一个 relay 中继日志中接着从库中有一个 SQL 线程会从中
继日志读取 binlog, 然后执行 binlog 日志中的内容, 也就是在自己本地再次执行一遍 SQL。

主从延迟:
a. 主库的从库太多
b. 从库硬件配置比主库差
c. 慢 SQL 语句过多
d. 主从库之间的网络延迟
e. 主库读写压力大
 

38、Spring 框架事务注解用什么注解? 使用该注解的失效场景

@Transactional
 Transactional 注解应用在非 public 修饰的方法上@Transactional 注解属性
propagation 设置错误
 @Transactional 注解属性 rollbackFor 设置错误
 同一个类中方法调用, 导致@Transactional 失效
 异常被 catch“ 吃了” 导致@Transactional 失效

39、I/O 多路复用实现方式有哪些

select
poll
epoll

40、如何保证 Redis 中的数据不丢失?

使用 AOF 和 RDB 结合的方式
RDB 做镜像全量持久化, AOF 做增量持久化。 因为 RDB 会耗费较长时间, 不够实时, 在
停机的时候会导致大量丢失数据, 所以需要 AOF 来配合使用
Redis 集群模式
master 节点持久化
Redis 断点续传
从 redis 2.8 开始, 就支持主从复制的断点续传, 如果主从复制过程中, 网络连接断掉了,
那么可以接着上次复制的地方, 继续复制下去, 而不是从头开始复制一份。
主备切换的过程, 可能会导致数据丢失
解决异步复制和脑裂导致的数据丢失
redis.conf 中
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有 1 个 slave, 数据复制和同步的延迟不能超过 10 秒
如果说一旦所有的 slave, 数据复制和同步的延迟都超过了 10 秒钟, 那么这个时候,
master 就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失。

41、如何保证 Redis 中的数据都是热点数据?

Redis 内存数据集大小上升到一定大小的时候, 就会施行数据淘汰策略。 Redis 提供 6 种
数据淘汰策略:
 volatile-lru: 从已设置过期时间的数据集( server.db[i].expires) 中挑选最近最少使用的
数据淘汰
 volatile-ttl: 从已设置过期时间的数据集( server.db[i].expires) 中挑选将要过期的数据
淘汰
 volatile-random: 从已设置过期时间的数据集( server.db[i].expires) 中任意选择数据
淘汰
 allkeys-lru: 从数据集( server.db[i].dict) 中挑选最近最少使用的数据淘汰
 allkeys-random: 从数据集( server.db[i].dict) 中任意选择数据淘汰
 no-enviction( 驱逐) : 禁止驱逐数据

42、MySQL 中有哪几种锁?

表级锁: 开销小, 加锁快; 不会出现死锁; 锁定粒度大, 发生锁冲突的概率最高, 并发度
最低。
行级锁: 开销大, 加锁慢; 会出现死锁; 锁定粒度最小, 发生锁冲突的概率最低, 并发度
也最高。
页面锁: 开销和加锁时间界于表锁和行锁之间; 会出现死锁; 锁定粒度界于表锁和行锁之
间, 并发度一般


43、描述 Synchronized、 ReentrantLock 的区别

 synchronized 是关键字, ReentrantLock 是 API 接口 Lock 需要手动加锁, 手动释放锁 synchronized 不可中断, ReentrantLock 可中断、 可超时 synchronized 是非公平锁, ReentrantLock 公平、 非公平皆可 ReentrantLock 支持 Condition, 多条件
  44、Java 面向对象包括哪些特性, 怎么理解的

封装:
继承:

多态:简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。

要实现多态需要做两件事:
第一: 方法重写( 子类继承父类并重写父类中已有的或抽象的方法) ;
第二: 对象造型( 用父类型引用指向子类型对象, 这样同样的引用调用同样的方法就会根据子
类对象的不同而表现出不同的行为) 。
抽象: 抽象是将一类对象的共同特征总结出来构造类的过程, 包括数据抽象和行为抽象两
方面。 抽象只关注对象有哪些属性和行为, 并不关注这些行为的细节是什么。
 

45、Spring 框架中用到了哪些设计模式

工厂设计模式 : Spring 使用工厂模式通过 BeanFactory、 ApplicationContext 创建bean 对象。代理设计模式 : Spring AOP 功能的实现。单例设计模式 : Spring 中的 Bean 默认都是单例的。模板方法模式 : Spring 中 jdbcTemplate、 hibernateTemplate 等以 Template 结尾的对数据库操作的类, 它们就使用到了模板模式。包装器设计模式 : 我们的项目需要连接多个数据库, 而且不同的客户在每次访问中根据需要会去访问不同的数据库。 这种模式让我们可以根据客户的需求能够动态切换不同的数据源观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、 spring MVC 中也是用到了适配器模式适配 Controller。
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/723679.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号