synchronized
关键字在 Java 中用于实现线程同步,确保多线程环境下对共享资源的安全访问。根据修饰的是静态方法还是非静态方法,其锁定的对象是不同的。
✅ 非静态方法(实例方法)
public synchronized void instanceMethod() {
// 同步代码块
}
-
锁对象:当前实例对象(
this
) -
作用范围:同一个实例的多个线程访问该方法时会互斥
-
不同实例之间:不会互斥,因为锁的是不同对象
示例:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
}
-
如果两个线程分别操作两个不同的
Counter
实例,它们不会互相阻塞。 -
如果两个线程操作同一个
Counter
实例,则increment()
会串行执行。
✅ 静态方法(类方法)
public static synchronized void staticMethod() {
// 同步代码块
}
-
锁对象:类的
Class
对象(即Counter.class
) -
作用范围:所有该类的实例共享同一把锁
-
即使多个线程操作不同实例,只要访问的是同一个类的静态同步方法,也会互斥
示例:
public class Counter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
}
-
无论多少个
Counter
实例,访问increment()
的线程都会被同步。
✅ 对比总结
特性 | 非静态同步方法 | 静态同步方法 |
---|---|---|
锁对象 | 当前实例 (this ) | 类的 Class 对象 |
作用范围 | 同一实例的线程互斥 | 所有实例的线程互斥 |
是否跨实例同步 | 否 | 是 |
使用场景 | 实例变量同步 | 静态变量或类级别资源同步 |
✅ 额外提示:同步代码块写法(更灵活)
你也可以手动指定锁对象:
// 锁当前实例
synchronized (this) {
// ...
}
// 锁类对象
synchronized (Counter.class) {
// ...
}
✅ 如果你有静态方法想同步怎么办?
如果你没有实例,但还想同步,那就不能用 this
,而要用类对象:
public class MyClass {
public static void staticMethod() {
synchronized (MyClass.class) {
System.out.println("静态同步代码块执行");
}
}
public static void main(String[] args) {
MyClass.staticMethod(); // ✅ 不需要实例,也能同步
}
}
✅ 一句话总结:
“锁当前实例”就是“锁对象”,只不过这个对象恰好是
this
(当前实例)而已。
🔍 详细解释
1. 锁的是对象,不是变量或代码
synchronized
锁的是对象本身,不是方法、变量或代码块。所以:
-
synchronized(this)
:锁的是当前实例对象(this
) -
synchronized(obj)
:锁的是你指定的那个对象(obj
) -
synchronized(Counter.class)
:锁的是Counter
的Class
对象(类锁)
2. “当前实例”就是“一个对象”
当你说“锁当前实例”,实际上就是在说“锁当前这个对象(this
)”。所以:
public synchronized void method() {
// 等价于 synchronized(this) { ... }
}
✅ 举个例子
假设你有一个类:
public class Account {
private int balance = 100;
public void withdraw(int amount) {
synchronized (this) { // 锁的是当前 Account 实例
if (balance >= amount) {
balance -= amount;
}
}
}
public static void printClassInfo() {
synchronized (Account.class) { // 锁的是 Account 的 Class 对象
System.out.println("Account class info...");
}
}
}
说法 | 实际含义 |
---|---|
锁当前实例 | 锁的是 this 这个对象 |
锁某个对象 | 锁的是你指定的那个对象 |
锁类对象 | 锁的是 ClassName.class |
✅ 所以,“锁当前实例”和“锁对象”没有本质区别,只是对象不同。关键是你锁的是哪个对象,决定了线程之间的互斥范围。
我是伏琪,关注订阅号伏琪了解更多。