1、作用:
保证在同一个时刻只能有一个线程运行该段代码(synchronized修饰的代码段或方法),以保证并发安全。
2、用法:
一个类可以有多个的实例对象,一个类只有一个class对象用于描述这个类,根据锁的对象的类型(普通实例对象,class对象)将用法分为对象锁和类锁。
(1)对象锁:锁的对象为普通实例对象,两种形式:(method1,method2)
方法锁(非static方法的锁对象为this即当前实例对象)和同步代码块锁(指定的锁对象)
(2)类锁:锁的对象为class对象,两种形式:(method3,method4)
修饰static方法(锁对象为当前类的class对象),指定锁为class对象
例子:
以上例子中method1和method2等价,method3和method4等价
类锁和对象锁的区别:当调用一个类的多个实例对象时,对象锁之间是不会互斥的,但类锁之间存在互斥。
3、性质
(1)可重入:同一个线程的外层函数获取到锁之后,内层函数可以直接再获取到该锁。可重入能够避免死锁,提高封装性不必再进行多次的加锁解锁操作。
(2)不可中断:如果一个线程A获取了锁之后,另一个线程B想获取该锁只能选择等待到线程锁A释放该锁,如果线程A一直不释放,那么B线程将永远的等待。线程A释放锁的两种方式:正常运行结束或抛出异常JVM自动释放锁。
4、原理:
(1)加锁释放锁原理:
加锁对应字节码:monitorenter #第6行对应进入synchronized修饰的代码块
释放锁对应字节码:monitorexit #第8,14行对应正常运行结束和抛出异常
(2)可重入性的原理:
通过加锁次数计数器,JVM会记录加锁的次数,每进入一次同步代码块加锁次数计数器会加1,退出一次同步代码块,加锁次数计数器会减1。
5、缺陷:
(1)效率低:锁的释放方式少,试图获取锁时不能设置超时,不能中断一个正在试图获取锁的线程。
(2)不够灵活:加锁和解锁的时机单一,每个锁只有单一的条件(某个对象)