首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

多線程共享數據的三種核心模式與最佳實踐

     編輯:Java 綜合教學

多線程環境下共享數據的訪問模式全解析

在多線程程序中,線程間共享數據是常態。根據「執行代碼是否相同」與「如何傳遞共享對象」,主要分為三大類實現模式。掌握這些模式,能幫助你寫出線程安全、結構清晰的並發代碼。

模式一:相同代碼,共享 Runnable 實例

適用場景:所有線程執行邏輯完全一致,如賣票系統、批量處理任務。

核心思想:創建 單一 Runnable 實例,多個 Thread 共享該實例,共享數據作為該實例的成員變量。

public class ShareRunnableDemo {
    public static void main(String[] args) {
        ShareData shareData = new ShareData();  // 單一共享對象
        new Thread(shareData).start();          // 線程 A
        new Thread(shareData).start();          // 線程 B
    }

    static class ShareData implements Runnable {
        private int count = 100;

        @Override
        public void run() {
            while (count > 0) {
                decrease();                     // 同步方法保護共享變量
            }
        }

        public synchronized void decrease() {   // 方法鎖 = this (shareData 實例)
            count--;
            System.out.println(Thread.currentThread().getName() + " count: " + count);
        }
    }
}

關鍵點:synchronized 修飾實例方法,鎖對象是 shareData 實例本身,兩線程爭奪同一把鎖,實現互斥。


模式二:不同代碼,共享獨立數據對象 (推薦)

適用場景:線程職責不同(如生產者/消費者),但需操作同一份數據。

核心思想:將共享數據及其操作封裝在獨立類中,將該對象引用傳遞給各 Runnable 實例。這樣「數據與操作綁定」,便於實現封裝性、互斥與通信。

public class IndependentDataObjectDemo {
    public static void main(String[] args) {
        ShareData shareData = new ShareData();           // 獨立共享數據對象
        new Thread(new Decrease(shareData)).start();     // 消費者線程
        new Thread(new Increment(shareData)).start();    // 生產者線程
    }

    // 消費者任務
    static class Decrease implements Runnable {
        private final ShareData shareData;
        public Decrease(ShareData shareData) { this.shareData = shareData; }
        @Override public void run() { shareData.decrease(); }
    }

    // 生產者任務
    static class Increment implements Runnable {
        private final ShareData shareData;
        public Increment(ShareData shareData) { this.shareData = shareData; }
        @Override public void run() { shareData.increment(); }
    }

    // 共享數據封裝類:數據 + 操作 + 同步控制
    static class ShareData {
        private int count = 100;
        public synchronized void decrease() { count--; /* ... */ }
        public synchronized void increment() { count++; /* ... */ }
    }
}

優勢:職責清晰分離,ShareData 內聚了數據與同步邏輯,Runnable 實現類只負責任務調度,符合「高內聚、低耦合」。


模式三:不同代碼,內部類訪問外部類成員

適用場景:邏輯較簡單,不想創建額外類文件,將共享數據作為外部類成員,各任務作為內部類。

public class InnerClassDemo {
    private static int count = 100;              // 外部類靜態成員作為共享數據

    public static void main(String[] args) {
        new Thread(new Decrease()).start();
        new Thread(new Increment()).start();
    }

    // 外部類提供同步操作方法
    public static synchronized void decrease() { count--; /* ... */ }
    public static synchronized void increment() { count++; /* ... */ }

    // 內部類任務直接調用外部類方法
    static class Decrease implements Runnable {
        @Override public void run() { decrease(); }
    }
    static class Increment implements Runnable {
        @Override public void run() { increment(); }
    }
}

注意:此處鎖對象是 InnerClassDemo.class (靜態方法鎖類對象)。若用實例方法,鎖則是外部類實例。


模式四:綜合應用 — 匿名內部類 + 獨立數據對象 (實戰常用)

結合模式二與三:共享數據封裝為獨立對象,任務用匿名內部類表達,代碼緊湊且結構清晰。

public class AnonymousInnerDemo {
    public static void main(String[] args) {
        final ShareData shareData = new ShareData();  // final 保證引用不變

        new Thread(() -> {          // Java 8 Lambda 簡化匿名內部類
            while (true) shareData.decrease();
        }).start();

        new Thread(() -> {
            while (true) shareData.increment();
        }).start();
    }

    static class ShareData {
        private int count = 100;
        public synchronized void decrease() { count--; /* ... */ }
        public synchronized void increment() { count++; /* ... */ }
    }
}

總結與最佳實踐建議

模式適用場景鎖對象推薦指數
共享 Runnable邏輯完全相同的線程組Runnable 實例⭐⭐
獨立數據對象線程職責不同,需共享數據數據對象實例⭐⭐⭐⭐⭐ (首選)
內部類訪問外部成員簡單邏輯、原型驗證外部類實例/Class⭐⭐
匿名內部類 + 獨立對象實際項目開發數據對象實例⭐⭐⭐⭐

核心原則:

  1. 封裝性:將需同步的操作封裝為獨立方法,置於同一類中(如 ShareData),便於統一加鎖。
  2. 最小化鎖範圍:只鎖保護共享變量的必要代碼塊。
  3. 不可變性優先:能用 final/Immutable 就不用鎖。
  4. 高級工具優先:實戰中優先考慮 AtomicInteger、ConcurrentHashMap、BlockingQueue 等 JUC 組件,減少手動同步錯誤。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved