1.synchronized的三种用法和区别?

(1)修饰普通方法 :当前实例加锁,进入同步代码前要获得当前实例的锁;
(2)修饰静态方法 :当前类加锁,进去同步代码前要获得当前类对象的锁;
(3)修饰代码块:这需要指定加锁的对象,对所给的指定对象加锁,进入同步代码前要获得指定对象的锁


2.synchronized和lock的区别?

Synchronized和Lock比较. Synchronized是关键字,内置语言实现,Lock是接口。. Synchronized在线程发生异常时会自动释放锁,因此不会发生异常死锁。. Lock异常时不会自动释放锁,所以需要在finally中实现释放锁。. Lock是可以中断锁,Synchronized是非中断锁,必须等待线程执行完成释放锁。. Lock可以使用读锁提高多线程读效率


3.synchronized实现原理?

Java 虚拟机是通过进入和退出 Monitor(毛嫩特儿) 对象来实现代码块同步和方法同步的代码块同步使用的是 monitorenter 和 monitorexit 指令实现的,而方法同步是通过 Access flags 后面的标识来确定该方法是否为同步方法。


4.CAS和ABA?

独占锁(ABA):是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。

乐观锁(CAS):每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功为止
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。


5.对象的锁升级过程?

过程可以概括为:
无锁(new对象)-偏向锁-轻量级锁(无锁,自旋锁如CAS,自适应锁)-重量级锁

刚new对象,是无锁状态,加锁编程偏向锁,有人征用,升级为轻量锁,竞争频繁,升级为重量级锁。

偏向锁:当线程调用到这个对象的时候,在mark word里面,用54位记录了指向当前线程的指针,说明这个锁当前属于该线程;epoch先不讲;1位没有用到;偏向锁位由0变成1;

轻量级锁:当有别的线程来竞争锁的时候,取消偏向锁;62位里面存的是指向某个线程lock record的指针,当有别的线程过来需要竞争锁的时候,(线程的线程栈里会有LR(lock record),去竞争锁,看谁能把指针指向该锁,CAS,线程去修改mark word的指向LR的指针,CAS),所以叫做自旋锁。

重量级锁:有些线程自旋超过10次,或者等着的线程超过CPU线程的一半,JDK1.6之后,JVM自适应自选,自己来控制上述参数。锁升级为重量级锁。 Mark word里62位指向的是重量级锁的指针(重量级锁需经过内核批准)。那么线程会进入一个该锁的队列,在队列里等待,是不消耗cpu的。

锁降级:特定情况下会发生,比如在GC的时候,因此没啥意义。
image.png

6.谈谈死锁的理解

当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。

7.死锁产生的四个必要条件

互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
循环等待条件:在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。
以上给出了导致死锁的四个必要条件,只要系统发生死锁则以上四个条件至少有一个成立。事实上循环等待的成立蕴含了前三个条件的成立,似乎没有必要列出然而考虑这些条件对死锁的预防是有利的,因为可以通过破坏四个条件中的任何一个来预防死锁的发生。