Java 線程同步的核心是多線程共享同一個鎖物件。本文展示兩種構建共享鎖的經典模式:外部傳遞模式與靜態成員模式。
// 任務類:實現 Runnable,接收外部鎖
class SharedLockTask implements Runnable {
private final int threadId;
private final Object lock; // 共享鎖引用
public SharedLockTask(int id, Object lock) {
this.threadId = id;
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) { // 競爭同一把鎖
for (int i = 0; i < 100; i++) {
System.out.println("Thread ID: " + threadId + " : " + i);
}
}
}
}
// 啟動類
public class ExternalLockDemo {
public static void main(String[] args) throws InterruptedException {
Object sharedLock = new Object(); // 單一鎖物件
for (int i = 0; i < 10; i++) {
new Thread(new SharedLockTask(i, sharedLock)).start();
Thread.sleep(1); // 錯峰啟動,觀察輸出順序
}
}
}
每個線程完整印出 0-99,無交叉輸出,證明同步生效。
class StaticLockTask implements Runnable {
private final int threadId;
// 類載入時初始化,所有實例共享
private static final Object LOCK = new Object();
public StaticLockTask(int id) {
this.threadId = id;
}
@Override
public void run() {
synchronized (LOCK) {
for (int i = 0; i < 100; i++) {
System.out.println("Thread ID: " + threadId + " : " + i);
}
}
}
}
public class StaticLockDemo {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Thread(new StaticLockTask(i)).start(); // 無需傳遞鎖
Thread.sleep(1);
}
}
}
| 維度 | 外部傳遞鎖 | static 靜態鎖 |
|---|---|---|
| 靈活性 | 高(可注入不同鎖實現隔離) | 低(硬編碼類級共享) |
| 封裝性 | 較差(鎖洩漏到建構子參數) | 優(鎖為私有實現細節) |
| 繼承行為 | 子類需顯式傳遞 | 子類自動共享父類鎖 |
| 測試友善度 | 極佳(可注入測試專用鎖) | 需反射或 PowerMock 修改 |
| 序列化影響 | 無 | static 不序列化,反序列化後仍共享 |
| 類載入器隔離 | 不受影響 | 不同 ClassLoader 載入會有多份鎖 |
// 1. synchronized(this) —— 只有同一實例才同步
synchronized (this) { ... } // 不同實例互不阻塞!
// 2. synchronized(getClass()) —— 繼承類會有不同 Class 物件
synchronized (getClass()) { ... } // 子類實例不阻塞父類實例!
// 3. synchronized("lock") —— 字串常量池共享,全 JVM 可見
synchronized ("global") { ... } // 極度危險:非預期跨模組阻塞
// 實例級鎖:私有 final 物件
private final Object instanceLock = new Object();
// 類級鎖:私有 static final 物件
private static final Object classLock = new Object();
// 方法級同步(隱含 this/class 鎖,慎用)
public synchronized void instanceMethod() { }
public static synchronized void staticMethod() { }
// 實例級
private final Lock lock = new ReentrantLock();
// 類級
private static final Lock lock = new ReentrantLock();
// 使用
lock.lock();
try {
// 臨界區
} finally {
lock.unlock(); // 必須在 finally 中釋放
}
優勢:可中斷、超時、公平性、多條件變數、非區塊結構鎖定。
共享鎖是 Java 同步的靈魂。外部傳遞模式適合需靈活控制共享範圍的框架代碼;static 靜態鎖適合業務邏輯內部同步。切記:鎖物件必須 final、不可變、私有,避免 this、getClass()、字串常量等「隱性共享」陷阱。現代專案優先考慮 ReentrantLock 或 java.util.concurrent 高層工具。