Java面试题整理
1.事务的四大特性?
名称 | 说明 |
---|---|
原子性 | 事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。一个事务内的操作要么全部成功要么全部失败 |
一致性 | 事务执行后,数据库状态与其它业务规则保持一致。其他特性都是为了给一致性服务的. 例如转账,张三给李四转账, 转账前和转账后张三和李四的所有钱数之和是保持不变的(事务操作的前后数据值一致) |
隔离性 | 事务和事务之间是隔离开的. 一个事务看不到另一个事务正在操作的数据(正在进行中的状态)(例如:两个人在两个房间考试,你做你的我做我的,相互隔离,互不影响)(事务与事务之前是相互隔离的) |
持久性 | 一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制将数据恢复到提交后的状态。 举例: 一般的数据操作只是在事务中记录需要进行这样的操作, 即使看到了表中的数据发生了改变, 实际上表中的数据也没有发生改变只是在事务中记录需要进行这样的操作, 真正提交了事务才去表中改变表中的数据 |
MySql中的事务:
- start transaction;(开启事务)
- rollback;(回滚事务):
- commit;(提交事务)
- quit; (中断操作-会退出mysql的cmd窗口)
MySQL中的隔离级别:
- 读未提交(read-uncommitted):安全性最差,容易出现脏读、不可重复读、幻读,但性能最高
- 读已提交(read-committed):安全性一般,可防止脏读,不能防止不可重复读、幻读
- 可重复读(repeatable-read):安全性较好,可防止脏读、不可重复读,但不能防止幻读
- 串行化(serialiable):安全性最好,可以防止一切事务并发问题,但是性能最差(不用)。
2.@Transactional注解有哪些参数?
参数 | 说明 |
---|---|
isolation | 事务隔离级别,默认为DEFAULT |
propagation | 事务传播机制,默认为REQUIRED |
readOnly | 事务读写性,默认为false(只读) |
noRollbackFor | 一组异常类,遇到时不回滚,默认为{} |
noRollbackForClassName | 一组异常类名,遇到时不回滚,默认为{} |
rollbackFor | 一组异常类,遇到时回滚,默认为{} |
rollbackForClassName | 一组异常类名,遇到时回滚,默认为{} |
timeout | 超时时间,以秒为单位 |
value | 可选的限定描述符,指定使用的事务管理器,默认为 "" |
@Transactional 注解的失效场景
- @Transactional 应用在非 public 修饰的方法上,不支持回滚;
- @Transactional 注解属性 propagation 设置错误;
- @Transactional 注解属性 rollbackFor 设置错误;
- 在同一个类中方法调用,导致 @Transactional 失效;
- 异常被你的 catch 处理了,导致 @Transactional 没办法回滚而失效;
- 数据库配置了不支持事务的引擎,或者数据库本身就不支持事务。
3.Spring事务的传播机制有哪些?
4.HashMap是线程安全的吗?有什么线程安全的Map?ConcurrentHashMap如何保证线程安全?
- HashMap不保证线程安全
有什么线程安全的Map?
名称 | 说明 |
---|---|
ConcurrentHashMap | JDK1.7 ConcurrentHashMap采⽤了数组+Segment+分段锁的⽅式实现 ==== JDK1.8 ConcurrentHashMap采⽤了数组+链表+红⿊树的实现⽅式来设计,内部⼤量采⽤CAS操作 |
Hashtable | 增、删操作采⽤synchronized⽅法上加锁,使⽤阻塞同步,效率低 |
Collections.synchronizedMap | 更不可取,也是采⽤synchronized⽅法上加锁,使⽤阻塞同步,效率低。 |
CopyOnWriteMap | 采⽤ 写时复制 的操作 写时复制: 当对容器进⾏增加,删除,修改操作时,不是直接操作容器,⽽是先将当前容器copy,复制出⼀个新的容器,再对新容器进⾏操作,操作完成后再将指针指向这个新容器。这样做的好处是我们可以对CopyOnWrite容器进⾏并发的读(CopyOnWriteArrayList底层使⽤数组实现,⽽该数组是被volatile修饰),⽽不⽤对其进⾏加锁,当然写的时候是需要加锁的(这⾥采⽤了lock加锁),否则可能copy出了N个副本 |
5.ReentrantLock 和 Synchronized 有什么区别?
- 相同点:
- 都是可重入锁,都是排他锁
- 不同点:
- 1.Synchronized 的加锁和解锁以及使用哪个锁: 由jvm决定
ReentrantLock 加锁解锁以及使用哪个锁: 由自己决定 - 2.ReentrantLock(功能更丰富,是以实现锁的限时等待,公平锁) 实际上比 Synchronized 更重量级一点
- 3.Synchronized 不能实现公平锁,限时等待功能
要用锁就使用Lock - 4.原理也有不同:
- Synchronized 的锁在对象的一个对象头标志位;
会出现锁升级: 开始"很轻",越到后面越重.性能不稳定 - ReentrantLock 的锁实际上是AbstractQueuedSynchronizer对象的一个属性(int state)
性能很稳定,总是一个轻量级改法
- Synchronized 的锁在对象的一个对象头标志位;
- 1.Synchronized 的加锁和解锁以及使用哪个锁: 由jvm决定
6.常用的linux命令有哪些?
命令 | 作用 |
---|---|
find / -name a.txt |
查找当前目录下文件名为a.txt的文件 |
ls -l | grep '.jar' |
查找当前目录中的所有jar文件 |
find . -name "*.xml" |
递归查找所有的xml文件 |
ps -ef | grep tomcat |
查看一个程序是否运行 |
kill -9 999 |
终止线程 |
ls -al |
查看文件,包含隐藏文件 |
pwd |
当前工作目录 |
cp source dest , cp -r sourceFolder targetFolder |
复制文件,递归复制 |
mkdir newfolder ,touch a.txt |
创建文件夹,创建文件 |
rmdir folder ,rm -rf deleteFile |
删除目录 , 递归删除目录中所有内容 |
mv /temp/source /target ,mv oldFileName newFileName |
移动文件,重命名 |
su -username |
切换用户 |
chmod 777 qiuqiu.java |
修改文件权限 |
tar -czf test.tar.gz /test1 /test2 |
压缩文件 |
tar -xvzf test.tar.gz -C |
解压文件 |
head -n 10 example.txt ,tail -n 10 example.txt |
查看文件头10行,查看文件尾10行 |
tail -f exmaple.log |
查看日志类型文件 |
sudo rm a.txt |
使用超级管理员身份执行命令 |
netstat -tln | grep 8080 |
查看端口占用情况 |
ps aux | grep java ,ps aux |
查看端口属于哪个程序,查看所有进程 |
curl http://ip:port/a |
发请求 |
ping www.baidu.com |
网络检测 |
echo $JAVA_HOME |
打印信息 |
java javac jps ,jstat ,jmap, jstack,JVisualVM |
java 常用命令 |
7.MySQL(GBK编码下)有个字符串"coder秋秋520"它们的char_length()和length()函数的值?
- GBK:一个汉字是2字节
length():是按照字节统计的,
coder秋秋520
所以值为:12
char_length():是按照字符统计的,coder秋秋520
所以值为:10
- UTF-8:一个汉字是3字节
length():是按照字节统计的,
coder秋秋520
所以值为:14
char_length():是按照字符统计的,coder秋秋520
所以值为:10
8.什么是死锁?
-
死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下,这些线程会一直相互等待而无法继续运行下去
-
死锁产生的原因
互斥条件:该资源任意一个时刻只由一个线程占用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件: 线程已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
循环等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系。
- 如何避免线程死锁?
1.破坏互斥条件
这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
2.破坏请求与保持条件
一次性申请所有的资源。
3.破坏不剥夺条件
占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
4.破坏循环等待条件
靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
9.SpringBoot配置文件加载顺序
注意:bootstrap会优先于application加载
10.Java如何判断对象已死亡?
- 引用计数法:
程序给对象添加一个引用计数器,每有一个变量引用它时计数器加1,当引用断开时计数器减一。当计数器为0时,代表没有任何变量引用他,该对象就死亡状态,JVM需要对此类对象进行回收。此计数法无法回收具有循环引用的对象,由于对象相互引用,导致各自计数器都不为0,导致JVM无法回收。
- 可达性分析法:
程序由GC Roots作为起点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,证明此对向是不可用的。 Java中,作为GC Roots的对象有一下几种:
1.虚拟机栈(栈帧中的本地变量表)中的引用对象
2.方法区中类静态属性引用的对象
3.方法区中常量引用的对象
4.本地方法栈(native方法)中引用的对象
11.@Configuration和@Bean的区别
// @Configuration底层还是@Component,凡是使用了此注解的Bean对象它的类型都是一个代理类对象,通过getBean(传入此类的class)无法获取
// @Bean则是什么类型就是什么类型
12.Spring整合Mybaits会出现一级缓存失效
spring结合mybatis后,一级缓存作用:
- 在未开启事物的情况之下,每次查询,spring都会关闭旧的sqlSession而创建新的sqlSession,因此此时的一级缓存是没有启作用的
- 在开启事物的情况之下,spring使用threadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的
13.synchronized底层实现是什么?lock底层是什么?有什么区别?
-
Synchronize同步代码块是通过monitorenter和monitorexit两个操作指令来维护同步的。jvm执行monitorenter指令时会视图抢一下monitorexit对象的所有权,如果抢占成功则将锁计数器 +1。如果没有抢占成功则会进入阻塞状态,知道其他线程释放锁。如果执行monitorexit指令会将锁计数器-1,当锁对象计数为0时将会释放锁。
-
Lock锁底层是通过CAS+自旋,底层是一个int类型锁的状态值,一个是双向链表AQS:同步抽象队列器(双向链表比单向链表多的就是 前驱指针,前驱指针就是指向了上一个节点, 那访问的时间复杂度就是O(1)了。 否则就需要遍历链表,时间复杂度就变成O(N)了。)工作原理就是通过CAS修改int status的状态值,没有抢到锁的线程就进入同步抽象队列器等待
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构