一、synchronized的使用场景
1.1、某个对象实例内
public void test3(){
synchronized (this){
}
}
通过字节码分析synchronized底层如何实现
- 先用
javac -encoding utf-8 SynchronizeTest.java
编译出class文件 - 再用
javap –v SynchronizeTest.class
查看字节码文件
分析字节码文件
通过字节码文件观测到它是通过monitorenter和monitorexit来实现。
monitorenter和monitorexit作用
每一个对象都有一个monitor监视器,调用monitorenter就是尝试获取这个对象,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,那么就把锁的计数器(_count)加1,当执行monitorexit时,锁的计数器-1,直到0时,释放锁。
两个monitorexit的作用
编辑器需要确保方法中调用过来的每条monitorenter指令都要被对应的monitorexit执行,确保异常时,monitorenter和monitorexit指令也能正常配对执行,编辑器会自动产生一个异常处理器,目的就是用来执行异常的monitorexit指令,而字节码多出的monitorexit指令,就是异常结束时,被执行用来释放monitor。
1.2、修饰在方法上
public synchronized void test1(){
}
public static synchronized void test2(){
}
分子字节码文件:
ACC_SYNCHRONIZED
同步方法是通过ACC_SYNCHRONIZED实现的,但是他的底层也是monitorenter和monitorexit来实现,因此本质是一样。
二、使用synchronized注意事项
- synchronized关键字不能被继承
如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,必须显式地在子类的这个方法中加上synchronized关键字才可以。
lass Parent {
public synchronized void test() { }
}
class Child extends Parent {
public synchronized void test() { }
}
当子类调用父类的同步方式时,使用super关键字修饰
class Parent {
public synchronized void test2() { }
}
class Child extends Parent {
public void method() { super.test2(); }
}
- 在定义接口方法时不能使用synchronized关键字。
三、synchronized的特点:
-
保证原子性,可见性,有序性
-
可重入性(某个线程已经获得某个锁,可再次获取锁而不会出现死锁)
可重入锁有:
-
Synchronized
-
ReentrantLock