首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 多線程 synchronized 陷阱:不同實例的同步方法互不阻塞

     編輯:程式設計疑難解答

問題代碼現象

class MyThread extends Thread {
    synchronized void fun1() { ... }
    synchronized void fun2() { ... }
    synchronized void fun3() { ... }
    public synchronized void run() {
        fun1(); fun2(); fun3();
    }
}

Thread a = new MyThread("線程1");
Thread b = new MyThread("線程2");
a.start(); b.start();
// 輸出交替執行,未同步!

根本原因:鎖對象不同

  • synchronized 實例方法鎖的是 this(當前對象實例)。
  • a 和 b 是兩個不同的 MyThread 實例,各自擁有獨立的鎖。
  • a.run() 鎖 a,b.run() 鎖 b,互不干擾 → 並發執行。

正確同步方案

方案一:共享同一把鎖(傳入同一實例)

MyThread shared = new MyThread("共享");
Thread a = new Thread(shared); // 實現 Runnable 接口更合適
Thread b = new Thread(shared);
a.start(); b.start(); // 現在會串行執行 fun1→fun2→fun3

方案二:使用 static synchronized 鎖類對象

class MyThread extends Thread {
    public static synchronized void fun1() { ... } // 鎖 MyThread.class
    // 所有實例共享類鎖
}

方案三:顯式鎖對象(推薦)

class SharedResource {
    private final Object lock = new Object();
    public void fun1() { synchronized(lock) { ... } }
    public void fun2() { synchronized(lock) { ... } }
}

// 多線程注入同一 SharedResource 實例

關鍵知識點總結

同步方式鎖對象作用範圍
synchronized 實例方法this同一實例的所有同步方法互斥
synchronized 靜態方法Class 對象所有實例的該靜態方法互斥
synchronized(this)this同塊代碼互斥
synchronized(共享對象)共享對象持有該對象引用的線程互斥

最佳實踐

  • 優先用 java.util.concurrent.Lock(ReentrantLock)替代 synchronized,支持超時、可中斷、公平鎖。
  • 封裝共享狀態到線程安全類中,避免在調用方手動加鎖。
  • 線程類繼承 Thread 不如實現 Runnable 靈活(支持線程池、共享實例)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved