6、Synchronized与Lock原理
1)、Synchronized与Lock区别:
a)、synchronized是一个关键字,在代码执行时出现异常,JVM会自动释放锁,
Lock是一个接口,要保证锁被释放,就必须在finally中执行unLock();
b)、synchronized属于隐式锁,不能实现公平锁;
Lock是显式锁,可实现公平锁,可以对锁进行控制,可以中断
c)、synchronized作用在static方法上时候,为全局锁;作用在非static方法上时,为对象锁
2)、Synchronized原理:
Synchronized作用于方法时:
JVM可以从方法常量池中的方法表结构(method_info Structure) 中的
ACC_SYNCHRONIZED访问标志区分一个方法是否同步方法。当方法调用时,
调用指令将会 检查方法的ACC_SYNCHRONIZED访问标志是否被设置,
如果设置了,执行线程将先持有monitor,然后再执行方法,最后再方法完成
(无论是正常完成还是非正常完成)时释放monitor。在方法执行期间,
执行线程持有了monitor,其他任何线程都无法再获得同一个monitor。
如果一个同步方法执行期间抛 出了异常,并且在方法内部无法处理此异常,
那这个同步方法所持有的monitor将在异常抛到同步方法之外时自动释放。
Synchronized作用于同步代码块时:
通过一个monitor(监视器锁)的对象来完成,使用monitorenter 和 monitorexit指令,
monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的
结束位置,当执行monitorenter指令时当monitor被占用时就会处于锁定状态,线程执行
monitorenter指令时尝试获取对象所对应的monitor所有权,倘若其他线程已经拥有
对象的 monitor所有权,那当前线程将被阻塞,直到正在执行线程执行完毕,
即monitorexit指令被执行。流程如下:
a)、如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,
该线程即为monitor的所有者。
b)、如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.
c)、如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的
进入数为0,再重新尝试获取monitor的所有权。
3)、Lock原理:
Lock实现类是ReetrantLock。ReetrantLock是基于AQS(AbstractQueuedSynchronizer又
称为队列同步器)并发框架实现的。
AQS原理:
内部通过一个int类型的成员变量state来控制同步状态,当state=0时,则说明没有
任何线程占有共享资源的锁,当state=1时,则说明有线程目前正在使用共享变量,
其他线程必须加入同步队列(FIFO的双向链表队列)进行等待,AQS内部通过
内部类Node构成FIFO的同步队列来完成线程获取锁的排队工作,同时利用内部类
ConditionObject构建等待队列,当Condition调用wait()方法后,线程将会加入
等待队列中,而当Condition调用signal()方法后,线程将从等待队列转移动
同步队列中进行锁竞争。注意这里涉及到两种队列,一种的同步队列,当线程请求锁
而等待的后将加入同步队列等待,而另一种则是等待队列(可有多个),通过Condition
调用await()方法释放锁后,将加入等待队列。
ReetrantLock原理:
重入锁ReentrantLock,是一个基于AQS并发框架的并发控制类,其内部实现了3个类,
分别是Sync、NoFairSync、FairSync类,其中Sync继承自AQS,实现了释放锁的
模板方法tryRelease(int),而NoFairSync和FairSync都继承自Sync,实现各种
获取锁的方法tryAcquire(int)。ReentrantLock的所有方法实现几乎都间接调用了
这3个类
附上一个ReentrantLock(源码解析流程)流程图(网上找的):