public synchronized void accessVal(int newVal) { ... }
public static synchronized void staticMethod() { ... }
this (當前實例)ClassName.class (類對象)synchronized(syncObject) {
// 受保護代碼
}
syncObject 可為任意物件:this、其他實例、ClassName.class、字串常量、專用鎖物件正解:synchronized 可用於任何類的方法/塊中。只要有多線程並發訪問共享資源,即需同步,與類是否繼承 Thread 或實現 Runnable 無關。
正解:本質相同,鎖的是括號內的物件。差別在於鎖對象的選擇策略:
| 場景 | 推薦鎖對象 | 說明 |
|---|---|---|
| 同步實例方法/塊,保護實例變量 | this | 當前實例唯一,天然適合 |
| 同步靜態方法/塊,保護靜態變量 | MyClass.class | 類對象全局唯一 |
| 多個實例需協同同步 | 共享的 Object lock = new Object() | 顯式鎖對象,語義清晰 |
| 調用其他物件的同步方法 | 被調用物件實例 | synchronized(otherObj) { otherObj.method(); } |
public class SharedResource {
public void methodA() {
// synchronized(this) { // 等價於方法加 synchronized
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " A i=" + i);
}
// }
}
public void methodB() {
// synchronized(this) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " B i=" + i);
}
// }
}
}
public class WorkerA implements Runnable {
private final SharedResource resource;
public WorkerA(SharedResource resource) { this.resource = resource; }
@Override
public void run() {
synchronized (resource) { // 鎖住 resource 實例
resource.methodA();
}
}
}
public class WorkerB implements Runnable {
private final SharedResource resource;
public WorkerB(SharedResource resource) { this.resource = resource; }
@Override
public void run() {
synchronized (resource) { // 同一把鎖
resource.methodB();
}
}
}
public class Main {
public static void main(String[] args) {
SharedResource res = new SharedResource();
new Thread(new WorkerA(res), "Thread-A").start();
new Thread(new WorkerB(res), "Thread-B").start();
}
}
輸出將顯示 Thread-A 完整執行 100 次 methodA,隨後 Thread-B 執行 methodB(或相反順序),不會交叉輸出。因為兩線程競爭同一把鎖 (res 實例)。
synchronized("lock") 危險!字串常量池全局共享,可能導致無關代碼意外互斥synchronized(Integer.valueOf(1)) 同理,緩存池導致共享this (子類實例),正常工作tryLock(timeout) (ReentrantLock)、避免巢狀同步ReentrantLock、ReadWriteLock、StampedLock、ConcurrentHashMap 等 JUC 組件理解 synchronized 的鎖對象語義,是編寫正確、高效並發程序的基石。