Java Synchronized锁原理学习笔记
一、 静态方法 vs 实例方法
核心区别:归属权不同
| 特性 | 静态方法 (static) | 实例方法 (无 static) |
| 归属 | 属于 类 (Class) | 属于 对象 (Object) |
| 调用 | 类名.方法() |
对象名.方法() |
| 内存 | 随类加载存在,常驻方法区 | 随对象创建存在,位于堆内存 |
| 访问权限 | 只能访问静态成员 (不能用 this) |
可访问实例成员 + 静态成员 |
| 典型用途 | 工具类 (Math.max)、工厂方法 | 操作对象具体数据 (user.getName) |
比喻:静态方法是“图纸上的说明书”(不依赖房子),实例方法是“房子里的功能”(必须先盖好房子)。
二、 锁的本质:我们在锁什么?
synchronized 关键字虽然写在方法上,但它锁住的永远是 对象。
1. 锁对象的对应关系
-
实例方法锁 (
synchronized void method())-
🔒 锁住的是:
this(当前具体的实例对象)。 -
效果:只限制对同一个对象的并发访问。
-
-
静态方法锁 (
static synchronized void method())-
🔒 锁住的是:
类名.class(全局唯一的 Class 对象)。 -
效果:限制对该类所有对象的并发访问(全局锁)。
-
-
代码块锁 (
synchronized(obj) { ... })-
🔒 锁住的是:
()里的那个对象。 -
灵活性:这是最灵活的方式,可以锁
this,锁Class,也可以锁自定义的private lock。
-
三、 锁的互斥(干扰)判断原则
判断两块代码是否互斥,只看一点:它们抢的是不是同一个对象?
| 场景 | 结果 | 原因 |
| 静态锁 vs 实例锁 | ✅ 互不干扰 | 一个锁 Class,一个锁 this,对象不同。 |
代码块 sync(this) vs 实例锁 |
❌ 互相干扰 | 都在抢当前对象 this。 |
代码块 sync(Class) vs 静态锁 |
❌ 互相干扰 | 都在抢全局的 Class 对象。 |
代码块 sync(lockObj) vs 任何方法锁 |
✅ 互不干扰 | lockObj 是独立的,与 this 或 Class 无关。 |
四、 关键概念辨析
1. this 指的是什么?
-
定义:
this是一个动态指针,代表**“当前调用这个方法的对象”**。 -
口诀:谁调用,
this就指向谁。 -
静态方法无
this:因为静态方法属于类,调用时可能还没有对象实例,所以不存在“我”的概念。
2. 锁的“君子协定” (最重要误区) ⚠️
-
误区:以为
synchronized(lock) { count++ }会物理锁住count变量,让别人无法访问。 -
真相:
-
锁住的只是
lock这个对象(像一个令牌/红绿灯)。 -
防君子不防小人:如果另一个线程不检查
lock(不加synchronized),直接去访问count,它是完全可以访问并修改的!
-
-
结论:锁并不是给数据加了保险箱,而是强制要求所有想要访问数据的线程遵守同一套排队规则。
五、 黄金法则 (Best Practices)
为了保证线程安全,必须遵循以下规则:
-
统一锁对象:对于同一个共享资源(如变量
count),所有访问它的入口(读操作和写操作),必须使用同一个锁对象进行同步。 -
避免混用:不要一会儿用
synchronized(this),一会儿用static synchronized来保护同一个变量,因为它们是两把不同的锁。 -
推荐做法:使用
private final Object lock = new Object();作为专用锁对象,避免外部代码通过锁住this来干扰内部逻辑。
更多推荐
所有评论(0)