Java面试题总结(四)

31.多线程锁的升级原理是什么?

什么是锁升级(锁膨胀)?
  JVM优化synchronized的运行机制,当JVM检测到不同的竞争状态时,就会根据需要自动切换到合适的锁,这种切换就是锁的升级。升级是不可逆的,也就是说只能从低到高,也就是无锁->偏向锁->轻量级锁->重量级锁,不能够降级
锁分级别原因:
没有优化以前,synchronized是重量级锁(悲观锁),使用 wait 和 notify、notifyAll 来切换线程状态非常消耗系统资源;线程的挂起和唤醒间隔很短暂,这样很浪费资源,影响性能。所以 JVM 对 synchronized 关键字进行了优化,把锁分为 无锁、偏向锁、轻量级锁、重量级锁 状态。
无锁:没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功,其他修改失败的线程会不断重试直到修改成功。
偏向锁:对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续的执行中自动获取锁,降低获取锁带来的性能开销。偏向锁,指的就是偏向第一个加锁线程,该线程是不会主动释放偏向锁的,只有当其他线程尝试竞争偏向锁才会被释放。
偏向锁的撤销,需要在某个时间点上没有字节码正在执行时,先暂停拥有偏向锁的线程,然后判断锁对象是否处于被锁定状态。如果线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁;
如果线程处于活动状态,升级为轻量级锁的状态。
轻量级锁:轻量级锁是指当锁是偏向锁的时候,被第二个线程 B 所访问,此时偏向锁就会升级为轻量级锁,线程 B 会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能。
当前只有一个等待线程,则该线程将通过自旋进行等待。但是当自旋超过一定的次数时,轻量级锁便会升级为重量级锁;当一个线程已持有锁,另一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁。
重量级锁:指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。
重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。
自旋理解
很多synchronized里面的代码只是一些很简单的代码,执行时间非常快,此时等待的线程都加锁可能是一种不太值得的操作,因为线程阻塞涉及到用户态和内核态切换的问题。既然synchronized里面的代码执行地非常快,不妨让等待锁的线程不要被阻塞,而是在synchronized的边界做忙循环,这就是自旋。如果做了多次忙循环发现还没有获得锁,再阻塞,这样可能是一种更好的策略。

32.怎么防止死锁?

死锁和产生死锁的四个必要条件以及如何避免和预防死锁

33.ThreadLocal 是什么?有哪些使用场景?

我是如何用一个 “ThreadLocal ” 狂虐面试官的?
呵呵,你这是在背面试题吧?ThreadLocal使用中会有那些坑?
https://cloud.tencent.com/developer/article/1658750?areaId=106001
https://www.zhihu.com/question/338650108
  ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
ThreadLocal并不是一个Thread,而是Thread的局部变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal中的几个主要方法:
void set(Object value)设置当前线程的线程局部变量的值。
public Object get()该方法返回当前线程所对应的线程局部变量。
public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
ThreadLocal的应用场景
1、方便同一个线程使用某一对象,避免不必要的参数传递;
2、线程间数据隔离(每个线程在自己线程里使用自己的局部变量,各线程间的ThreadLocal对象互不影响);
3、获取数据库连接、Session、关联ID(比如日志的uniqueID,方便串起多个日志);
其中spring中的事务管理器就是使用的ThreadLocal:
  Spring的事务管理器通过AOP切入业务代码,在进入业务代码前,会依据相应的事务管理器提取出相应的事务对象,假如事务管理器是DataSourceTransactionManager,
就会从DataSource中获取一个连接对象,通过一定的包装后将其保存在ThreadLocal中。而且Spring也将DataSource进行了包装,重写了当中的getConnection()方法,或者说
该方法的返回将由Spring来控制,这样Spring就能让线程内多次获取到的Connection对象是同一个。

34.说一下 synchronized 底层实现原理?

深入理解synchronized底层原理,一篇文章就够了!
synchronized的四种用法

35.synchronized 和 volatile 的区别是什么?

volatile 关键字,你真的理解吗?
volatile 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
volatile 仅能使用在变量级别;synchronized 则可以使用在方法、代码块和类级别
volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性
volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化
使用volatile而不是synchronized的唯一安全情况是类中只有一个可变的域。

36.synchronized 和 Lock 有什么区别?

synchronized 是Java内置关键字,在jvm层面,Lock是个java类。
synchronized 无法判断是否获取锁的状态,Lock可以通过trylock来知道有没有获取锁。
synchronized 会自动释放锁,Lock 需要在 finally 中手工释放锁(unlock() 方法释放锁),否则容易造成线程死锁。
用 synchronized 关键字的两个线程1和线程2,如果当前线程1获得锁,线程2等待。如果线程1堵塞了,线程2会一直等待下去;而Lock 锁就不一定会等待下去,如果尝试获取不到锁,线程可以不同一直等待就结束了。
synchronized 的锁可重入、不可中断、非公平,而 Lock 锁可重入、可判断、可公平。
Lock 锁适合大量同步代码的同步问题,而 synchronized 锁适合代码少量的同步问题。
lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断。
synchronized使用Object对象本身的wait 、notify、notifyAll调度机制,而Lock可以使用Condition进行线程之间的调度。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时,此时Lock的性能要远远优于synchronized。

37.synchronized 和 ReentrantLock 区别是什么?

synchronized 是Java中的关键字,ReentrantLock是类,这是二者本质区别。既然 ReentrantLock 是类,那么它就提供了比synchronized 更多灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock 比synchronized 的扩展性体现在几点上:

ReentrantLock 可以对获取锁的等待时间进行设置,这样就避免了死锁发生
ReentrantLock 可以获取各种锁的信息
ReentrantLock 可以灵活的实现多路通知
另外,二者的锁机制其实也是不一样的,ReentrantLock 底层调用的是 Unsafe的park 方法加锁,synchronized 操作的应该是对象头中的 mark word。

38.说一下 atomic 的原理?

Java并发编程包中atomic的实现原理

39.什么是反射?

Java 反射详解

40.什么是 java 序列化?什么情况下需要序列化?

面试官:您能说说序列化和反序列化吗?是怎么实现的?什么场景下需要它?

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值