一、synchronized的用法
1、修饰同步方法
Public synchronized void methodName(){
……
}
2、修饰同步静态方法
Public synchronized static void methodName(){
……
}
3、修饰同步代码块(对象)
synchronized(this|object) {
……
}
4、修饰同步代码块(CLASS)
synchronized(类.class) {
……
}
二、对象锁与类锁
1、获取对象锁(修饰非静态方法)
在 Java 中,每个对象都会有一个 monitor 对象,这个对象其实就是 Java 对象的锁,通常会被称为“内置锁”或“对象锁”。类的对象可以有多个,所以每个对象有其独立的对象锁,互不干扰。
synchronized(this|object) {}
2、获取类锁(修饰静态方法)
在 Java 中,针对每个类也有一个锁,可以称为“类锁”,类锁实际上是通过对象锁实现的,即类的 Class 对象锁。每个类只有一个 Class 对象,所以每个类只有一个类锁。
synchronized(类.class) {}
三、 monitor 对象
在 Java 中,每个对象都会有一个 monitor 对象,监视器。
1) 某一线程占有这个对象的时候,先monitor 的计数器是不是0,如果是0还没有线程占有,这个时候线程占有这个对象,并且对这个对象的monitor+1;如果不为0,表示这个线程已经被其他线程占有,这个线程等待。当线程释放占有权的时候,monitor-1;
2) 同一线程可以对同一对象进行多次加锁,+1,+1,重入性
四、synchronized原理分析
1、JVM指令分析
javap -v class的名字进行反编译
以上是代码块的加锁monitorenter和monitorExit配合使用
>以上是对方法的加锁
2、使用synchronized注意的问题
(1)与moniter关联的对象不能为空
(2)synchronized作用域太大
(3)不同的monitor企图锁相同的方法
(4)多个锁的交叉导致死锁
3、Java虚拟机对synchronized的优化
1.6JDK以前重量锁,1.6之后加入了偏向锁和轻量级锁
被hashcode的对象不可用作偏向锁 wait 之后的锁一定是重量级锁 |
对象头与monitor的关系:一个对象实例包含:对象头、实例变量、填充数据
无锁状态:没有加锁
偏向锁:在对象第一次被某一线程占有的时候,是否偏向锁置1,锁表01,写入线程号,当其他的线程访问的时候,竞争失败。此时锁不会立即升级为轻量级锁,而是自旋一会,根据CAS算法尝试获取锁,若还是没有得到就会升级为轻量级锁,但是很多次被第一次占有它的线程获取,就会是偏向锁。
CAS算法 campany and set(CAS)
无锁状态时间非常接近,竞争不激烈的时候适用
轻量级锁:线程有交替适用,互斥性不是很强,CAS失败,00
重量级锁:强互斥,10,等待时间长
自旋锁:竞争失败的时候,不是马上转化级别,而是执行几次空循环
锁消除:JIT在编译的时候吧不必要的锁去掉