Java 线程同步核心是共享资源的访问控制。JVM 中线程共享的数据包括:
每个对象或类关联一个监视器,监视器通过对象锁(隐式锁)实现互斥。类锁本质也是通过 Class 对象实现。锁支持重入:同一线程可多次获取同一锁,JVM 维护计数器,计数器归零才释放。
synchronized (共享对象引用) {
// 临界区
}
显式指定锁对象,灵活控制锁粒度。
synchronized void method() → 锁是 this(当前实例)。static synchronized void method() → 锁是 当前类.class 对象。// 错误示例:每个线程持有不同锁
public class TestThread extends Thread {
@Override
public synchronized void run() { // 锁是 this,每个线程 this 不同
for (int i = 0; i < 1000; i++) {
System.out.println("NO." + threadNum + ":" + i);
}
}
}
10 个线程各自创建 TestThread 实例,锁对象不同,无法互斥,输出交错。
public class TestThread extends Thread {
private final String sharedLock; // 共享字符串对象
public TestThread(int threadNum, String sharedLock) {
this.threadNum = threadNum;
this.sharedLock = sharedLock;
}
@Override
public void run() {
synchronized (sharedLock) { // 同步块指定共享锁
for (int i = 0; i < 1000; i++) {
System.out.println("NO." + threadNum + ":" + i);
}
}
}
public static void main(String[] args) {
String lock = "sharedLock"; // 单一共享对象
for (int i = 0; i < 10; i++) {
new TestThread(i, lock).start();
}
}
}
所有线程同步于同一 sharedLock,输出按序执行。
public class TestThread extends Thread {
public static synchronized void staticTest(int threadNum) {
for (int i = 0; i < 1000; i++) {
System.out.println("NO." + threadNum + ":" + i);
}
}
@Override public void run() { staticTest(threadNum); }
}
静态方法锁住 TestThread.class,所有线程共享类锁,自然同步。
| 形式 | 锁对象 | 适用场景 |
|---|---|---|
| 同步代码块 | 指定对象引用 | 精细控制锁粒度、非 this 锁 |
| 实例同步方法 | this(当前实例) | 简单场景,需单例或共享实例 |
| 静态同步方法 | 当前类.class | 类级共享资源,天然全局互斥 |
核心原则:同步必须锁定共享对象,否则同步失效。