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

Java 多線程核心機制與同步控制詳解

     編輯:Java 綜合教學

Java 多線程核心機制與同步控制詳解

在 Java 開發中,多線程是實現高併發、提升程序執行效率的關鍵技術。本文系統梳理線程基礎概念、創建方式、生命週期狀態、線程安全問題及同步解決方案,並以單例模式雙重檢查鎖為例展示實戰應用。

一、核心概念辨析

  • 程序:靜態代碼集合,以文件形式存儲於磁盤。
  • 進程:程序的一次動態執行,擁有獨立地址空間。
  • 線程:進程內的執行路徑,是 CPU 調度的基本單位。多線程並非真正同時運行,而是 CPU 高速切換產生的並發假象。

二、線程生命週期五大狀態

  1. 創建:new Thread() 或子類實例化
  2. 運行:佔用 CPU 執行 run() 方法
  3. 阻塞:具備執行資格但未搶佔到 CPU
  4. 凍結:無執行資格,如 sleep()、wait() 狀態
  5. 消亡:run() 執行完成或異常終止

三、線程創建兩大範式

1. 繼承 Thread 類

class PrintNum extends Thread {
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
    public PrintNum(String name) { super(name); }
}

public class TestThread {
    public static void main(String[] args) {
        PrintNum p1 = new PrintNum("線程1");
        PrintNum p2 = new PrintNum("線程2");
        p1.setPriority(Thread.MAX_PRIORITY);
        p2.setPriority(Thread.MIN_PRIORITY);
        p1.start(); p2.start();
    }
}

三步驟:創建線程 → 重寫 run() → 調用 start() 啟動。

2. 實現 Runnable 接口(推薦)

class SubThread implements Runnable {
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        SubThread s = new SubThread();
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        t1.setName("線程1"); t2.setName("線程2");
        t1.start(); t2.start();
    }
}

範式對比

維度繼承 Thread實現 Runnable
適用場景無父類繼承、簡邏輯需共享數據、避免單繼承限制
數據共享每個線程獨有數據同一 Runnable 實例天然共享
匿名內部類適合一次性任務同樣支援

四、線程安全問題與同步機制

經典售票案例:非線程安全

class TicketSeller implements Runnable {
    private int tickets = 100;
    public void run() {
        while (true) {
            if (tickets > 0) {
                // 模擬網絡延遲暴露問題
                try { Thread.sleep(3); } catch (Exception e) {}
                System.out.println(Thread.currentThread().getName() + " 第" + tickets-- + "票");
            }
        }
    }
}

兩個窗口可能賣出同一張票(如第 0 張),因「檢查-執行」非原子操作。

同步解決方案

核心原理:鎖機制,同一時間只允許一線程進入同步區。

1. 同步代碼塊
synchronized (鎖對象) {
    // 共享資源操作
}

鎖可為任意對象,建議用共享資源本身或 new Object()。

2. 同步方法
public synchronized void sell() { ... }
  • 實例方法鎖:this
  • 靜態方法鎖:類名.class
前提條件
  1. 多線程環境
  2. 共用同一把鎖

五、實戰:單例模式雙重檢查鎖

class Singleton {
    private static volatile Singleton instance = null;
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {                    // 第一次檢查,避免不必要同步
            synchronized (Singleton.class) {       // 類級別鎖
                if (instance == null) {            // 第二次檢查,確保單例
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

關鍵點:

  • volatile 禁止指令重排,保證可見性
  • 代碼塊鎖比方法鎖粒度細,性能更優
  • 靜態方法鎖用 Singleton.class

六、最佳實踐總結

  1. 優先選 Runnable + 線程池,解耦任務與執行
  2. 共享可變狀態必須同步,鎖粒度越小越好
  3. 善用 java.util.concurrent 並發包(ReentrantLock、AtomicInteger、ConcurrentHashMap)
  4. 避免過早優化,先保證正確性
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved