Java基础

1. 面向对象的特征有哪些方面?

抽象、继承、封装、多态

2. 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

栈(stack):基本数据类型的变量,一个对象的引用,还有就是函数调用的现场
堆(heap):通过new 关键字和构造器创建的对象
方法区(method area):方法区和堆都是各个线程共享的内存区域,用于存储已经被 JVM 加载的类信息、常量、静态变量、JIT 编译器编译后的代码等数据

  1. // 变量 str 放在栈上,用 new 创建出来的字符串对象放在堆上,而”hello”这个字面量是放在方法区的
  2. String str = new String("hello");

3. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的

4. String 和 StringBuilder、StringBuffer 的区别?

String 是只读字符串
StringBuilder是在单线程环境下使用,是线程不安全的
StringBuffer是线程同步的

5. 重载(Overload)和重写(Override)的区别

前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重载对返回类型没有特殊的要求。
重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。

6. char 型变量中能不能存贮一个中文汉字,为什么?

一个汉字=2字节 中文标点占三个字节,一个英文字母占一个字节,英文标点占一个字节。

7. GC 是什么?为什么要有 GC?

与垃圾回收相关的 JVM 参数:

-Xms / -Xmx — 堆的初始大小 / 堆的最大大小 -Xmn — 堆中年轻代的大小 -XX:-DisableExplicitGC — 让 System.gc()不产生任何作用 -XX:+PrintGCDetails — 打印 GC 的细节 -XX:+PrintGCDateStamps — 打印 GC 操作的时间戳 -XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小 -XX:NewRatio — 可以设置老生代和新生代的比例 -XX:PrintTenuringDistribution — 设置每次新生代 GC 后输出幸存者 乐园中对象年龄的分布 -XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老 年代阀值的初始值和最大值 -XX:TargetSurvivorRatio:设置幸存区的目标使用率

8. 简述 synchronized 和 java.util.concurrent.locks.Lock的异同?

相同点:Lock 能完成 synchronized 所实现的所有功能;
主要不同点:Lock 有比synchronized 更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized 会自动释放锁,而 Lock 一定要求程序员手工释放,并且最好在 finally 块中释放(这是释放外部资源的最好的地方)。

9. 在进行数据库编程时,连接池有什么作用?

由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行 TCP 的三次握手,释放连接需要进行 TCP 四次握手,造成的开销是不可忽视的),为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接。

10. 事务的 ACID 是指什么?

编号80,并发数据访问时问题详解
(1)原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
(2)一致性(Consistent):事务结束后系统状态是一致的;
(3)隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
(4)持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

11. 阐述 ArrayList、Vector、LinkedList 的存储性能和特性

ArrayList 和 Vector 都是使用数组方式存储数据,索引数据快而插入数据慢,
Vector 是线程安全的容器,性能上较ArrayList 差。
LinkedList 使用双向链表实现存储,索引慢插入快,非线程安全。
Vector 属于遗留容器,已经不推荐使用,如果遇到多个线程操作同一个容器的场景,则可以通过工具类Collections 中的 synchronizedList 方法将其转换成线程安全的容器后再使用。

12.Thread 类的 sleep()方法和对象的 wait()方法都可以让线程暂停执行,它们有什么区别?

sleep()方法(休眠)是线程类(Thread)的静态方法,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复
wait()是 Object 类的方法,调用对象的 wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的 notify()方法(或 notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

13. 线程的基本状态以及状态之间的关系?

IMG_20210323_085411.jpg
其中 Running 表示运行状态,Runnable 表示就绪状态(万事俱备,只欠CPU),Blocked 表示阻塞状态,阻塞状态又有多种情况,可能是因为调用 wait()方法进入等待池,也可能是执行同步方法或同步代码块进入等锁池,或者是调用了 sleep()方法或 join()方法等待休眠或其他线程结束,或是因为发生了 I/O 中断。

14.Java 中如何实现序列化,有什么意义?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间
要实现序列化,需要让一个类实现 Serializable 接口,该接口是一个标识性接口,标注该类对象是可被序列化的.。

15.获得一个类的类对象有哪些方式?

(1)方法 1:类型.class,例如:String.class
(2)方法 2:对象.getClass(),例如:”hello”.getClass()
(3)方法 3:Class.forName(),例如:Class.forName(“java.lang.String”)

16.如何通过反射创建对象?

方法 1:通过类对象调用 newInstance()方法,例如:String.class.newInstance()

方法 2:通过类对象的 getConstructor()或 getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其 newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);

17. JRE、JDK、JVM 及 JIT 之间有什么不同?

JRE 代表 Java 运行 时(Java run-time),是 运 行 Java 引用所必须的
JDK 代表 Java 开发工具(Java development kit),是 Java 程序的开发工具,如 Java编译器,它也包含 JRE
JVM 代表 Java 虚拟机(Java virtual machine),它的责任是运行 Java 应用
JIT 代表即时编译(Just In Time compilation),当代码执行的次数超过一定的阈值时,会将 Java 字节码转换为本地代码,这样有利大幅度提高 Java 应用的性能

18. 说出 5 个 JDK 1.8 引入的新特性?

(1)Lambda 表达式,允许像对象一样传递匿名函数
(2)Stream API,充分利用现代多核 CPU,可以写出很简洁的代码
(3)Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用
(4)扩展方法,现在,接口中可以有静态、默认方法。
(5)重复注解,现在你可以将相同的注解在同一类型上使用多次。

19. 设计模式

http://c.biancheng.net/design_pattern/
抽象工厂模式,是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
模板方法模式,定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。
策略(Strategy)模式,该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

Redis

1. 什么是 Redis?

Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key-value 数据库
(1)Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
(2)Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
(3)Redis 支持数据的备份,即 master-slave 模式的数据备份

2. Redis 的数据类型?

支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及 zsetsorted set:有序集合)

3. Redis 是单进程单线程的?

Redis 是单进程单线程的,redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。

4. Redis 的持久化机制是什么?各自的优缺点?Redis提供两种持久化机制 RDB 和 AOF 机制:

1、RDB(Redis DataBase)持久化方式:
是指用数据集快照的方式半持久化模式,记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优点:
(1)只有一个文件 dump.rdb,方便持久化
(2)容灾性好,一个文件可以保存到安全的磁盘。
(3)性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis的高性能)
(4)相对于数据集大时,比 AOF 的启动效率更高。

缺点:
数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候

2、AOF(Append-only file)持久化方式:
是指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储, 保存为 aof 文件
优点:
(1)数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 aof 文件中一次。
(2)通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。
(3)AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))
缺点:
(1)AOF 文件比 RDB 文件大,且恢复速度慢
(2)数据集大的时候,比 rdb 启动效率低

3. Redis 常见性能问题和解决方案:

(1)Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务
(2)如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一
(3)为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网
(4)尽量避免在压力很大的主库上增加从
(5)主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1<- Slave2 <- Slave3…这样的结构方便解决单点故障问题,实现 Slave 对 Master的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其他不变。

4. redis 过期键的删除策略?

(1)定时删除: 在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作。
(2)惰性删除: 放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
(3)定期删除: 每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。edis.conf中,hz默认设为10s。

5. Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?

Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson。
Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令的支持;Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等 Redis 特性。

6. 使用过 Redis 做异步队列么,你是怎么用的?

一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试

7. 使用过 Redis 分布式锁么,它是什么回事?

先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。

8. Redis key 的过期时间和永久有效分别怎么设置?

EXPIRE 和 PERSIST 命令

9. 哨兵

哨兵必须用三个实例去保证自己的健壮性的,哨兵+主从并不能保证数据不丢失,但是可以保证集群的高可用

  • 集群监控:负责监控 Redis master 和 slave 进程是否正常工作。
  • 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
  • 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
  • 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

10. 缓存穿透

缓存穿透。产生这个问题的原因可能是外部的恶意攻击,例如,对用户信息进行了缓存,但恶意攻击者使用不存在的用户id频繁请求接口,导致查询缓存不命中,然后穿透 DB 查询依然不命中。这时会有大量请求穿透缓存访问到 DB。
解决的办法如下。

  1. 对不存在的用户,在缓存中保存一个空对象进行标记,防止相同 ID 再次访问 DB。不过有时这个方法并不能很好解决问题,可能导致缓存中存储大量无用数据。
  2. 使用 BloomFilter 过滤器,BloomFilter 的特点是存在性检测,如果 BloomFilter 中不存在,那么数据一定不存在;如果 BloomFilter 中存在,实际数据也有可能会不存在。非常适合解决这类的问题。

    11. 缓存击穿

    缓存击穿,就是某个热点数据失效时,大量针对这个数据的请求会穿透到数据源。
    解决这个问题有如下办法。

  3. 可以使用互斥锁更新,保证同一个进程中针对同一个数据不会并发请求到 DB,减小 DB 压力。

  4. 使用随机退避方式,失效时随机 sleep 一个很短的时间,再次查询,如果失败再执行更新。
  5. 针对多个热点 key 同时失效的问题,可以在缓存时使用固定时间加上一个小的随机数,避免大量热点 key 同一时刻失效。

    12. 缓存雪崩

    缓存雪崩,产生的原因是缓存挂掉,这时所有的请求都会穿透到 DB。
    解决方法:

  6. 使用快速失败的熔断策略,减少 DB 瞬间压力;

  7. 使用主从模式和集群模式来尽量保证缓存服务的高可用。

实际场景中,这两种方法会结合使用。

13. Redis 删除数据后,为什么内存占用率还是很高?

1.内存分配策略局限性,- 般都会分配固定的空间大小,导致实际分配的内存空间大于实际申请
的,从而多出了许多不连续的空闲内存块。
2.键值对的修改、删除导致了内存的扩容或者释放,导致多余的不连续的空闲内存块。
image.pngimage.pngimage.png

14. 如何清理内存碎片?

1.重启redis
风险:未持久化,数据丢失;
持久化,AOF,RDB文件大时,恢复阶段无法提供服务
2.Redis 4.0-RC3版本之后,Redis自身提供了一种清除内存碎片的方法

  1. # 启动自动清理命令
  2. config set activedefrag yes

自定义清理策略
1. active-defrag- ignore -bytes 400mb :如果内存碎片达到了400mb,开始清理(自定义)
2. active -defrag- threshold- lower 20 :内存碎片空间占操作系统分配给Redis的总空间比例达
到20%时,开始清理(自定义)

多线程

Java多线程常用面试题(含答案,精心总结整理)

1. 什么是原子操作,Java中的原子操作是什么?

原子操作是不可分割的操作,一个原子操作中间是不会被其他线程打断的,所以不需要同步一个原子操作。

2. volatile和synchronized方法有什么不同?

volatile关键字的作用是:保证变量的可见性。
在java内存结构中,每个线程都是有自己独立的内存空间(此处指的线程栈)。当需要对一个共享变量操作时,线程会将这个数据从主存空间复制到自己的独立空间内进行操作,然后在某个时刻将修改后的值刷新到主存空间。这个中间时间就会发生许多奇奇怪怪的线程安全问题了,volatile就出来了,它保证读取数据时只从主存空间读取,修改数据直接修改到主存空间中去,这样就保证了这个变量对多个操作线程的可见性了。

volatile轻量级,只能修饰变量;
synchronized重量级,还可修饰方法。
volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞

3. java线程的状态

Java面试题 - 图5

  • 新建状态(New)

用new语句创建的线程处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。
就绪状态(Runnable)
当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态,Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权。

  • 运行状态(Running)

处于这个状态的线程占用CPU,执行程序代码。只有处于就绪状态的线程才有机会转到运行状态。

  • 阻塞状态(Blocked)

阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU。直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态可分为以下3种:

  • 位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。
  • 位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。
  • 其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。
    • 死亡状态(Dead)

当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。

4. Java中你怎样唤醒一个阻塞的线程?

如果线程因为调用wait()、sleep()、或者join()方法而导致的阻塞,你可以中断线程,并且通过抛出InterruptedException来唤醒它。

5. 创建线程的方式

继承thread类
实现runable接口
实现callable接口,有返回结果

6. Java 线程池中 submit() 和 execute()方法有什么区别?

两个方法都可以向线程池提交任务,execute()方法的返回类型是 void,它定义在Executor 接口中。

而 submit()方法可以返回持有计算结果的 Future 对象,它定义在ExecutorService 接口中,它扩展了 Executor 接口,其它线程池类像ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 都有这些方法。

7. 线程间通信方式

1.使用volatile关键字
volatile 关键字来实现线程间相互通信是使用共享内存的思想,大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。

2.使用Object类的wait() 和 notify() 方法

注意: wait和 notify必须配合synchronized使用,wait方法释放锁,notify方法不释放锁

3.使用JUC工具类 CountDownLatch
jdk1.5之后在java.util.concurrent包下提供了很多并发编程相关的工具类,简化了我们的并发编程代码的书写,CountDownLatch基于AQS框架,相当于也是维护了一个线程间共享变量state

JVM

SpringBoot

1. SpringMVC,Spring,SpringBoot区别

SpringMVC主要处理web开发的路径映射和视图渲染,属于spring框架中WEB层开发的一部分;
Spring是一个一站式的轻量级的java开发框架,核心是控制反转(IOC)和面向切面(AOP),针对于开发的WEB层(springMvc)、业务层(Ioc)、持久层(jdbcTemplate)等都提供了多种配置解决方案;
SpringBoot框架相对于springMvc框架来说,更专注于开发微服务后台接口,不开发前端视图,同时遵循默认优于配置,简化了插件配置流程,不需要配置xml,相对springmvc,大大简化了配置流程;springCloud框架来说,它和springBoot一样,注重的是微服务的开发,SpringCloud更关注的是全局微服务的整合和管理,相当于管理多个springBoot框架的单体微服务;

2. SpringBoot事务注解

https://blog.csdn.net/wkl305268748/article/details/77619367
@Transactional
readOnly true只读
rollbackFor 指定异常回滚
isolation 事务隔离级别
timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时

3. SpringBoot常用注解

1、@SpringBootApplication
包含@Configuration、@EnableAutoConfiguration、@ComponentScan
2、@RestController
包含@Controller和@ResponseBody
3、@EnableAutoConfiguration
让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置,一般加在主类上。
4、@RequestMapping
用来处理请求地址映射的注解

4. IOC,AOP实现原理

AOP两种实现方式:
JDK的动态代理:只能对实现了接口的类产生代理;缺点:必须让目标对象实现接口,才能使用JDK代理。如果目标对象实现接口,spring默认采用JDK代理
Cglib的动态代理: 可以对没有实现接口的类产生代理。产生了子类对这个类进行增强,如果目标对象没有实现接口,spring采用cglib代理

IOC:反射

5.有哪些不同类型的IOC(依赖注入)?

构造器依赖注入:构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每个参数代表注入的对象。
Setter方法依赖注入:首先容器会触发一个无参构造函数或无参静态工厂方法实例化对象,之后容器调用bean中的setter方法完成Setter方法依赖注入。

SpringSecurity

MySQL

集群

分库分表

Mycat + Keepalived

SQL慢查询

语雀内容

RabbitMQ

RabbitMQ

SpringCloud

语雀内容

项目介绍

西安交通大学学生成长辅助分析系统(学工)
框架:SpringBoot,mybatis,freemaker,MySQL。。。全局异常,aop统一返回json格式
功能模块:学生电子档案、特征分析、全息画像
遇到问题:jenkins自动继承服务部署,多线程生成学生毕业档案文件

单点登录

https://blog.csdn.net/xiaoguan_liu/article/details/91492110