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

Java 多線程核心技術全景:創建方式、同步機制、線程通信、鎖優化與並發包升級

     編輯:Java 綜合教學

線程與進程本質區別

維度進程線程
定義執行中程式的實例,資源分配單位進程內的執行路徑,調度執行單位
記憶體獨立地址空間共享進程堆/方法區,私有棧/PC寄存器
開銷創建/切換昂貴輕量級,上下文切換快
通信IPC (管道/套接字/共享內存)共享內存直接讀寫,需同步

四種線程創建方式對比

方式核心類/介面優點缺點推薦場景
1. 繼承 Threadclass MyThread extends Thread簡單直觀,this 即線程對象單繼承限制,邏輯與控制耦合簡單測試、教學演示
2. 實現 Runnableclass Task implements Runnable分離任務與執行,支援共享實例、線程池需包裝 new Thread(task)最通用推薦
3. 匿名內部類new Thread() { run() {...} }就地定義,適合一次性邏輯可讀性差,難複用簡單一次性任務
4. 實現 Callable + FutureTaskCallable<V>, FutureTask<V>有返回值、可拋異常、配合線程池稍繁瑣需結果/異常的異步計算

Runnable 共享實例線程安全示範

class CounterTask implements Runnable {
    private int count = 100;
    
    @Override public void run() {
        while (true) {
            synchronized (this) { // 共享實例 this 為鎖
                if (count <= 0) break;
                try { Thread.sleep(100); } catch (InterruptedException ignored) {}
                System.out.println(Thread.currentThread().getName() + " 剩餘: " + count--);
            }
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        CounterTask task = new CounterTask(); // 單一實例
        new Thread(task, "線程-A").start();
        new Thread(task, "線程-B").start();
        new Thread(task, "線程-C").start();
    }
}

關鍵:synchronized(this) 確保三線程互斥訪問共享 count,輸出 100→0 無重複無遺漏。

synchronized 鎖對象規則

同步形式鎖對象範圍
非靜態方法 synchronized void m()this同一實例所有非靜態同步方法互斥
靜態方法 synchronized static void m()ClassName.class全類所有靜態同步方法互斥
同步塊 synchronized(obj)obj (任意對象)自定義粒度,需確保共享同一鎖實例

wait/notify 精確線程通信

核心規則

  1. 必須在同步塊內:持有鎖才能調用
  2. 鎖對象調用:lock.wait()、lock.notify()
  3. wait 釋放鎖:進入等待集,被 notify 後重新競爭鎖
  4. notify 隨機喚醒一個,notifyAll 喚醒全部

經典生產者-消費者模式

class SharedBuffer {
    private final List buffer = new ArrayList<>();
    private final int capacity = 10;
    
    public synchronized void produce(int value) throws InterruptedException {
        while (buffer.size() == capacity) wait(); // 滿等待
        buffer.add(value);
        notifyAll(); // 喚醒消費者
    }
    
    public synchronized int consume() throws InterruptedException {
        while (buffer.isEmpty()) wait(); // 空等待
        int value = buffer.remove(0);
        notifyAll(); // 喚醒生產者
        return value;
    }
}

為什麼定義在 Object 而非 Thread?

鎖屬於任意對象,一個程式可有多把鎖。線程需在持有特定鎖的同步塊內調用該鎖的 wait/notify,故定義在 Object 通用。

線程生命週期與狀態轉換

NEW → (start) → RUNNABLE ↔ (時間片/鎖/IO) → BLOCKED/WAITING/TIMED_WAITING → (結束) → TERMINATED

線程狀態轉換圖

安全停止線程:中斷模式

已棄用:stop() (破壞鎖一致性)、suspend()/resume() (易死鎖)

標準協作式停止

class Worker implements Runnable {
    private volatile boolean running = true;
    
    public void run() {
        while (running && !Thread.currentThread().isInterrupted()) {
            try {
                // 業務邏輯
                TimeUnit.MILLISECONDS.sleep(200); // 可中斷阻塞
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 重設標誌
                break;
            }
        }
        // 清理資源
    }
    
    public void shutdown() { running = false; }
}

中斷方法對比

方法類型行為中斷標誌
interrupt()實例設置標誌;阻塞處拋 InterruptedException 並清除標誌設置/清除後可重設
isInterrupted()實例只讀檢查,不清除只讀
interrupted()static檢查當前線程並清除標誌讀取並清除

單例模式線程安全演進

懶漢式:雙重檢查鎖 (DCL) 最終版

public class Singleton {
    private static volatile Singleton instance; // volatile 禁止指令重排
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {                  // 第一次檢查:無鎖快速路徑
            synchronized (Singleton.class) {     // 類級鎖
                if (instance == null) {          // 第二次檢查:防重複創建
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

JDK 1.5+ 並發包升級:Lock 與 Condition

ReentrantLock 核心優勢

  • 可中斷獲取:lock.lockInterruptibly()
  • 非阻塞嘗試:lock.tryLock()、tryLock(timeout)
  • 公平鎖選項:new ReentrantLock(true)
  • 多條件變量:lock.newCondition() 精確喚醒

Condition 替代 wait/notify

class BoundedBuffer {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Object[] items = new Object[10];
    private int putPtr, takePtr, count;
    
    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) notFull.await(); // 精確等待
            items[putPtr] = x;
            if (++putPtr == items.length) putPtr = 0;
            ++count;
            notEmpty.signal(); // 只喚醒消費者
        } finally { lock.unlock(); }
    }
    
    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) notEmpty.await();
            Object x = items[takePtr];
            if (++takePtr == items.length) takePtr = 0;
            --count;
            notFull.signal(); // 只喚醒生產者
            return x;
        } finally { lock.unlock(); }
    }
}

對比優勢:notifyAll 驚群效應 vs signal 精確喚醒;多條件變量語義清晰;支援 awaitUninterruptibly、awaitUntil 等進階等待。

常用並發工具類速查

類用途核心方法
CountDownLatch一組線程等待計數歸零countDown(), await()
CyclicBarrier一組線程相互等待屏障點await(), barrierAction
Semaphore信號量控制並發訪問數acquire(), release()
Exchanger雙線程交換數據exchange(V)
Phaser多階段屏障 (JDK 7+)arriveAndAwaitAdvance()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved