前言:此关键字是 java 的内置锁关键字,不需要开发者手动去加锁和解锁,加锁和解锁都是有 jvm 来负责,使用起来较为方便。
- 锁需要共享的成员变量,例如常用的 map.
是否是可重入的? 是的。
通用流程
| 序号 | 内容 |
|---|---|
| 1 | 看到了锁,根据锁关联的对象,判断锁的级别 (实例级别、类级别) |
书写的几种类型
修饰方法
修饰代码块
注意,synchronized 方法和 synchronized 代码块无论是执行 return 还是抛出异常,都一定能释放锁。因为不需要开发者显示去加锁、解锁,这些逻辑都被 jdk 给封装好了,开发者直接标识同步区域就好了。
如果锁代码块 则使用 monitorenter 和 monitorexit 来进入临界区和出临界区
如果修饰方法 在方法的 ACC_FLAG 中会存在 ACC_SYNCHRONIZED 标识。
一个问题,下面这个代码是否有问题
Integer i = 0;
synchronized(i) {
i++;
}
看起来也是锁的类成员变量。 但其实是有问题的,因为 i 每次都会变,所以这里锁的对象每次都是不同的,所以加锁也失去了意义。
i++ 实际是创建了一个新的 Integer 对象,i = Integer.valueOf(i.intValue() + 1)。
解决方案:
- 使用原子变量 AtomicInteger 进行计数,这样就不用加锁。
- 使用专门的对象锁,另起一个锁对象。
永远不要锁可能改变引用的对象 锁对象应该是 final 的、不可变的