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

Java 多線程與同步機制深度解析:從實現原理到鎖優化

     編輯:Java 相關知識

多線程程式設計的核心挑戰在於「如何正確實現並行」與「如何安全共享資料」。本文系統梳理 Java 多線程實現方式、同步鎖機制、以及效能優化策略。

一、多線程實現的兩條路徑

1. 繼承 Thread 類別

覆寫 run() 封裝並行邏輯,透過 start() 啟動(切勿直接呼叫 run(),start() 會完成線程初始化再呼叫 run())。

public class TestThread extends Thread {
    private static int threadCount = 0;
    private int threadNum = ++threadCount;
    private int i = 5;
    
    public void run() {
        while (true) {
            try { Thread.sleep(100); } 
            catch (InterruptedException e) { System.out.println("Interrupted"); }
            System.out.println("Thread " + threadNum + " = " + i);
            if (--i == 0) return;
        }
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) new TestThread().start();
    }
}

輸出特徵:五個線程交替輸出,證明並行生效。注意:未持有引用的 Thread 物件不會被 GC 回收,因線程註冊機制會隱性持有引用。

2. 實作 Runnable 介面

突破單一繼承限制,將任務邏輯與線程控制分離:

public class TestThread implements Runnable {
    private static int threadCount = 0;
    private int threadNum = ++threadCount;
    private int i = 5;
    
    public void run() {
        while (true) {
            try { Thread.sleep(100); } 
            catch (InterruptedException e) { System.out.println("Interrupted"); }
            System.out.println("Thread " + threadNum + " = " + i);
            if (--i == 0) return;
        }
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) new Thread(new TestThread()).start();
    }
}

二、同步鎖的核心機制

1. 物件鎖與類別鎖

  • 非 static synchronized:鎖住具體物件實例(this),同一物件的不同線程互斥
  • static synchronized:鎖住類別物件(Class 物件),所有實例共享同一把鎖

2. 關鍵驗證:不同物件實例的線程可並行存取非 static 同步方法

class TestSynchronized implements Runnable {
    public synchronized void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try { Thread.sleep(100); } catch (InterruptedException e) {}
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        TestSynchronized r1 = new TestSynchronized();
        TestSynchronized r2 = new TestSynchronized();
        Thread t1 = new Thread(r1, "t1");
        Thread t2 = new Thread(r2, "t2"); // 兩個不同物件
        t1.start(); t2.start();
    }
}

結果:t1、t2 交替輸出,證明不同物件擁有獨立鎖,可並行執行。

3. 同一物件的多線程強制序列化

若 t2 = new Thread(r1, "t2") 共用 r1,輸出變為 t1 完整執行完再輪到 t2。

4. 物件鎖與類別鎖相互獨立

同一線程可同時持有物件鎖(執行 run())與類別鎖(呼叫 static prt()),互不阻塞。

三、同步區塊優化:縮小鎖粒度

僅同步必要程式碼區塊,提升並行度:

class TestSynchronized implements Runnable {
    static int j = 0;
    public void run() {
        for (int i = 0; i < 5; i++) {
            synchronized (this) {  // 僅保護 j++ 與列印
                System.out.println(Thread.currentThread().getName() + " : " + j++);
            }
            try { Thread.sleep(100); } catch (InterruptedException e) {}
        }
    }
}

效果:睡眠操作移出同步區塊,其他線程可在睡眠期間取得鎖並執行,輸出交替更頻繁,吞吐量顯著提升。

總結

  • 掌握 Thread 繼承與 Runnable 實作兩種模式,按場景選擇
  • 深入理解「鎖屬於物件」而非方法,同步範圍由物件實例決定
  • 善用 synchronized(this) { ... } 縮小臨界區,平衡安全與效能
  • 物件鎖(非 static)與類別鎖(static)獨立運作,可同時持有
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved