01. Synchronized
2020-08-26 本文已影响0人
哈哈大圣
一、Synchronized简介
- 作用:能够保证同一时刻最多只有一个线程执行该段代码,以达到保证并发安全效果。
- 地位:关键字;最基本的互斥同步手段
二、Synchronized的两种用法
1) 对象锁
- 实例方法锁:默认锁对象为
this
当前实例对象
synchronized void func(...) {
...
}
- 同步代码块锁:指定锁对象
synchronized(obj) {
...
}
2) 类锁
Java类可能有很多个对象,但只有一个Class对象
- Synchronized修饰的静态方法
synchronized static void func(...) {
...
}
- 指定锁为Class对象
synchronized(obj.class) {
...
}
三、多线程访问同步方法的7中情况(面试常考)
- 两个线程同时访问一个对象的同步方法
- 同步
- 两个线程访问的是两个对象的同步方法
- 不会同步干扰
- 两个线程访问的是synchronized的静态方法
- 同步
- 同时访问同步方法与非同步方法
- 同步方法会被同步
- 访问同一个对象的不同的普通方法
- 不会同步
- 同时访问静态synchronized和非静态的synchronized方法
- 使用同一个同步对象会进行同步
- 方法抛异常后,会释放锁
- synchronized修饰的方法以及代码块在程序抛出异常后会自动释放锁
四、Synchronized性质
- 可重入性
- 不可中断性
1) 可重入性
- 概念:同一线程的外层函数获得锁之后,内层函数可以在不释放锁的条件下直接再次获取该锁
- 好处:避免死锁、提升封装性
- 粒度:线程而非调用 (linux中的pthread的粒度为【调用】)
- 同一个方法是可重入的(递归)
- 可重入不要求是同一个方法
- 可重入不要求是同一个类中的
2) 不可中断性
- 概念:如果当前线程想要获取其他线程已经获得的锁,只能选择等待或者阻塞,直到别的线程释放对应的锁
Lock类, 可以发送中断信号(释放不释放关键看别人),停止等待获取锁的能力。
五、加锁和释放锁的原理
1) 加锁和释放锁的原理:现象、时机
- 获取和释放锁的时机:内置锁
- 反编译字节码文件
javap -verbose ClassName.class
-verbose的作用是打日志
monitorexit指令 (释放锁,计数器-1) ,出现次数可能多于monitorenter (获取锁,计数器+1) ,是因为走异常处理分支的时候出现的情况
2) 可重入原理:加锁次数计数器
- JVM负责跟踪对象被加锁的次数
- 线程第一次,计数变为1,对应线程再次加锁,变为2
- 每当任务离开,计数递减,当计数为0,锁被完全释放
3) 保证可见性的原理:内存模型大概介绍

每个线程都会有主内存的副本,当线程A同步任务执行完毕后,在释放锁之前会将本地内存修改的内容及时写入主内存,保证其他线程对该修改的可见性。
六、Synchronized的缺陷
-
效率低
- 锁的释放情况少
- 试图获得锁时不能设定超时
- 不能中断一个正在试图获得锁的线程
-
不够灵活:(读写锁更灵活)
- 加锁和释放锁的时机单一
- 每个锁仅有单一的条件(某个对象),可能是不够的
-
无法知道是否成功获取到锁
七、面试关键点
-
synchronized使用注意点:
- 锁对象不能为空:锁的信息是保存在对象头中的
- 作用域不易过大:synchronized包裹的范围
- 避免死锁
-
如何选择Lock与synchronized关键字?
- 如果可以,用JUC包中的工具类
- synchronized如果适用,则使用此,因为使用简单,不易出错
- 最后考虑Lock或者Condition
-
synchronized访问同步方法的各种具体情况分析(一般可以分为文档上述7种)
-
一句话总结synchronized(谈谈对synchronized的理解)
JVM会自动通过使用monitor来加锁和解锁,保证了同时只有一个线程
可以执行指定代码,从而保证了线程安全,同时具有可重入和不可中断的性质。
八、拓展
- synchronized锁竞争策略:非公平竞争
- synchronized同时只有一个线程可以执行,性能差,有什么办法可以提升性能?
- 优化使用范围
- 使用读写锁等替代方案