java面试宝典(26)

98 阅读6分钟

学习java.java企业级实战项目

  1. 怎么防止死锁?

死锁的四个必要条件:

互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源

请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放

不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放

环路等待条件:是指进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之 一不满足,就不会发生死锁。

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和 解除死锁。

所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确 定资源的合理分配算法,避免进程永久占据系统资源。

如上是万金油类的正确的废话,理论层面这样说总不会错,那么在实际操作中是怎么做的?

1 比如在数据库的数据隔离级别方面,别设太高,否则很容易引发数据库里的等待,乃至死锁。

2 预防死锁的代价要比监控死锁的代价大很多,所以系统里一般是监控+解决,比如用监控系统(Cat等),看是否有长时间运行的SQL语句或线程,这可以预先设置,比如运行时间超过60秒就报警,然后人工介入。

3 代码在上线前,在测试环境充分压力测试,发现死锁点再解决。上线后,不能保证一定没死锁,一般也是采用监控+人工解决的方式。

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

这是线程局部变量,属于线程自身私有,不在多个线程间共享。

Java提供ThreadLocal类来支持线程局部变量,是一种实现线程安全的方式。

请注意,任何线程局部变量一旦在工作完成后没有释放,Java 就会有内存泄露乃至OOM的风险。

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

synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。

Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:

普通同步方法,锁是当前实例对象

静态同步方法,锁是当前类的class对象

同步方法块,锁是括号里面的对象

  一旦有线程对上述对象加锁,那么其它线程进入前就会检查并等待,等到锁释放后再进入。

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

volatile是在告诉jvm当前变量在自身线程的内存区里,值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。

volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。

volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

  1. synchronized 和 Lock 有什么区别?

synchronized是java关键字,Lock是个java类;

synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;

synchronized会自动释放锁,Lock需在finally中手工释放锁(unlock()方法释放锁);

用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;

synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);

Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

结论: synchronized很重,而且大多只能加在单个方法上,而Lock可以作用在调用多个业务的方法上,使用起来比较简便。

  1. synchronized 和 ReentrantLock 区别是什么?

synchronized是关键字,ReentrantLock是类,这是二者的本质区别。

ReentrantLock是类,所以synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量

ReentrantLock比synchronized的扩展性体现在几点上: 

ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁 

ReentrantLock可以获取各种锁的信息

ReentrantLock可以灵活地实现多路通知 

另外,二者的锁机制其实也是不一样的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word。

  1. 说一下 atomic 的原理?

Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型封装类)变量进行操作时,具有排斥性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。

Atomic系列的类中的核心方法都会调用unsafe类中的几个本地方法。我们需要先知道一个东西就是Unsafe类,全名为:sun.misc.Unsafe,这个类包含了大量的对C代码的操作,包括很多直接内存分配以及原子操作的调用,而它之所以标记为非安全的

这个里面大量的方法调用都会存在安全隐患,需要小心使用,否则会导致严重的后果,例如在通过unsafe分配内存的时候,如果自己指定某些区域可能会导致一些类似C++一样的指针越界到其他进程的问题。

结论,你面试时说说就行了,实际项目里用的话需要非常谨慎。