欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的線程同步全面講解

 更新時(shí)間:2025年07月30日 08:29:54   作者:六七_(dá)Shmily  
線程同步指的是在多線程環(huán)境下,通過某種機(jī)制來協(xié)調(diào)多個(gè)線程對(duì)共享資源的訪問,確保在同一時(shí)刻只有一個(gè)線程能夠訪問共享資源,從而避免數(shù)據(jù)不一致和其他并發(fā)問題,這篇文章主要介紹了Java中線程同步的相關(guān)資料,需要的朋友可以參考下

前言

線程同步是多線程編程的核心概念,用于協(xié)調(diào)多個(gè)線程對(duì)共享資源的訪問,防止數(shù)據(jù)不一致和并發(fā)問題。下面我將全面講解 Java 中的線程同步機(jī)制。

一、為什么需要線程同步?

當(dāng)多個(gè)線程訪問共享資源時(shí),可能出現(xiàn):

  • 競(jìng)態(tài)條件:多個(gè)線程同時(shí)修改同一數(shù)據(jù)
  • 內(nèi)存可見性問題:一個(gè)線程修改數(shù)據(jù)后,其他線程看不到最新值
  • 指令重排序問題:編譯器/處理器優(yōu)化導(dǎo)致代碼執(zhí)行順序改變

二、Java 同步機(jī)制分類

1. 內(nèi)置鎖(synchronized)

// 同步方法
public synchronized void increment() {
    count++;
}

// 同步代碼塊
public void update() {
    synchronized(this) {
        // 臨界區(qū)代碼
    }
}

// 靜態(tài)方法鎖(類級(jí)別鎖)
public static synchronized void staticMethod() {
    // ...
}

特點(diǎn)

  • 自動(dòng)獲取/釋放鎖(進(jìn)入同步塊獲取,退出釋放)
  • 可重入(同一線程可重復(fù)獲取同一把鎖)
  • 非公平鎖(不保證等待時(shí)間最長(zhǎng)的線程先獲取鎖)

2. 顯式鎖(Lock API)

private final ReentrantLock lock = new ReentrantLock();

public void performTask() {
    lock.lock();  // 手動(dòng)加鎖
    try {
        // 臨界區(qū)代碼
    } finally {
        lock.unlock();  // 必須手動(dòng)釋放鎖
    }
}

Lock 接口優(yōu)勢(shì)

  • 可中斷鎖(lockInterruptibly()
  • 超時(shí)獲取鎖(tryLock(long time, TimeUnit unit)
  • 公平鎖選項(xiàng)(new ReentrantLock(true)
  • 多條件變量(Condition

3. 原子變量(Atomic Classes)

private AtomicInteger count = new AtomicInteger(0);

public void safeIncrement() {
    count.incrementAndGet();  // 原子操作
}

常用原子類

  • AtomicInteger, AtomicLong
  • AtomicReference
  • AtomicBoolean
  • LongAdder(高并發(fā)計(jì)數(shù)器)

4. volatile 關(guān)鍵字

private volatile boolean running = true;

public void stop() {
    running = false;  // 寫操作立即對(duì)其他線程可見
}

適用場(chǎng)景

  • 狀態(tài)標(biāo)志(單個(gè)寫入者)
  • 雙重檢查鎖定模式
  • 不保證復(fù)合操作的原子性

三、高級(jí)同步工具

1. 讀寫鎖(ReadWriteLock)

private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();

public String readData() {
    readLock.lock();
    try {
        return data;
    } finally {
        readLock.unlock();
    }
}

public void writeData(String value) {
    writeLock.lock();
    try {
        data = value;
    } finally {
        writeLock.unlock();
    }
}

2. 條件變量(Condition)

private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();

public void put(Object item) throws InterruptedException {
    lock.lock();
    try {
        while (queue.isFull()) {
            notFull.await();  // 等待隊(duì)列非滿
        }
        queue.enqueue(item);
        notEmpty.signal();  // 喚醒等待的消費(fèi)者
    } finally {
        lock.unlock();
    }
}

3. 同步集合

// 并發(fā)Map
Map<String, String> concurrentMap = new ConcurrentHashMap<>();

// 阻塞隊(duì)列
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(100);

// 寫時(shí)復(fù)制列表
List<String> safeList = new CopyOnWriteArrayList<>();

四、線程協(xié)調(diào)工具

1. CountDownLatch(一次性門閂)

CountDownLatch latch = new CountDownLatch(3);

// 工作線程
void worker() {
    // 執(zhí)行任務(wù)...
    latch.countDown();
}

// 主線程
latch.await();  // 阻塞直到計(jì)數(shù)歸零
System.out.println("所有任務(wù)完成");

2. CyclicBarrier(循環(huán)屏障)

CyclicBarrier barrier = new CyclicBarrier(4, () -> 
    System.out.println("所有玩家準(zhǔn)備就緒"));

void player() {
    prepare();
    barrier.await();  // 等待其他玩家
    startGame();
}

3. Semaphore(信號(hào)量)

Semaphore semaphore = new Semaphore(5); // 5個(gè)許可證

void accessResource() {
    semaphore.acquire();  // 獲取許可
    try {
        // 使用資源
    } finally {
        semaphore.release();  // 釋放許可
    }
}

4. Exchanger(數(shù)據(jù)交換器)

Exchanger<String> exchanger = new Exchanger<>();

// 線程A
String dataA = "Data from A";
String received = exchanger.exchange(dataA);

// 線程B
String dataB = "Data from B";
String received = exchanger.exchange(dataB);

五、避免死鎖的策略

1. 死鎖產(chǎn)生的必要條件

  • 互斥條件
  • 持有并等待
  • 不可搶占
  • 循環(huán)等待

2. 預(yù)防死鎖的方法

// 1. 固定鎖順序
public void transfer(Account from, Account to, int amount) {
    Account first = from.id < to.id ? from : to;
    Account second = from.id < to.id ? to : from;
    
    synchronized(first) {
        synchronized(second) {
            // 轉(zhuǎn)賬操作
        }
    }
}

// 2. 嘗試獲取鎖(帶超時(shí))
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
    try {
        if (lock2.tryLock(1, TimeUnit.SECONDS)) {
            try {
                // 操作
            } finally {
                lock2.unlock();
            }
        }
    } finally {
        lock1.unlock();
    }
}

// 3. 使用開放調(diào)用(避免在持有鎖時(shí)調(diào)用外部方法)

六、同步性能優(yōu)化

1. 減少鎖競(jìng)爭(zhēng)

  • 縮小同步范圍:同步代碼塊 > 同步方法
  • 降低鎖粒度:使用多個(gè)鎖代替單個(gè)鎖
  • 使用讀寫鎖:區(qū)分讀/寫操作
  • 無鎖數(shù)據(jù)結(jié)構(gòu):原子變量、CAS操作

2. 鎖消除與鎖粗化

// 鎖消除(JIT編譯器優(yōu)化)
public String concat(String s1, String s2, String s3) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);  // 同步方法但可消除鎖
    sb.append(s2);
    sb.append(s3);
    return sb.toString();
}

// 鎖粗化(減少頻繁加鎖開銷)
synchronized(lock) {
    operation1();
    operation2();
    operation3();
}

3. 并發(fā)設(shè)計(jì)模式

// 1. 生產(chǎn)者-消費(fèi)者模式
BlockingQueue<Task> queue = new LinkedBlockingQueue<>();

// 2. 線程局部存儲(chǔ)
private static ThreadLocal<SimpleDateFormat> dateFormat = 
    ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

// 3. Future模式
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Integer> future = executor.submit(() -> computeExpensiveValue());
// ...其他操作
Integer result = future.get();

七、Java內(nèi)存模型(JMM)與同步

Happens-Before 規(guī)則

  1. 程序順序規(guī)則
  2. 監(jiān)視器鎖規(guī)則
  3. volatile變量規(guī)則
  4. 線程啟動(dòng)規(guī)則
  5. 線程終止規(guī)則
  6. 中斷規(guī)則
  7. 終結(jié)器規(guī)則
  8. 傳遞性
// 正確同步示例
class SafePublication {
    private int value;
    private volatile boolean initialized;
    
    public void initialize(int val) {
        value = val;
        initialized = true;  // volatile寫
    }
    
    public int getValue() {
        if (initialized) {   // volatile讀
            return value;
        }
        return -1;
    }
}

八、現(xiàn)代同步實(shí)踐

1. CompletableFuture(異步編程)

CompletableFuture.supplyAsync(() -> fetchData())
    .thenApply(data -> process(data))
    .thenAccept(result -> store(result))
    .exceptionally(ex -> handleError(ex));

2. StampedLock(樂觀讀鎖)

private final StampedLock lock = new StampedLock();
private double balance;

public double readBalance() {
    long stamp = lock.tryOptimisticRead();  // 樂觀讀
    double currentBalance = balance;
    if (!lock.validate(stamp)) {  // 檢查是否被修改
        stamp = lock.readLock();  // 退化為悲觀讀
        try {
            currentBalance = balance;
        } finally {
            lock.unlockRead(stamp);
        }
    }
    return currentBalance;
}

3. VarHandle(Java 9+)

class AtomicCounter {
    private volatile int count;
    private static final VarHandle COUNT_HANDLE;
    
    static {
        try {
            COUNT_HANDLE = MethodHandles.lookup()
                .findVarHandle(AtomicCounter.class, "count", int.class);
        } catch (Exception e) {
            throw new Error(e);
        }
    }
    
    public void increment() {
        int current;
        do {
            current = (int) COUNT_HANDLE.getVolatile(this);
        } while (!COUNT_HANDLE.compareAndSet(this, current, current + 1));
    }
}

九、同步機(jī)制選擇指南

場(chǎng)景推薦方案說明
簡(jiǎn)單同步synchronized開發(fā)簡(jiǎn)單,自動(dòng)管理
復(fù)雜鎖控制ReentrantLock支持超時(shí)、中斷等
讀多寫少ReentrantReadWriteLock提高讀并發(fā)性能
計(jì)數(shù)器AtomicInteger/LongAdder無鎖高性能
狀態(tài)標(biāo)志volatile輕量級(jí)可見性保證
線程協(xié)作CountDownLatch/CyclicBarrier協(xié)調(diào)多線程執(zhí)行
資源池Semaphore控制并發(fā)訪問數(shù)量
異步編程CompletableFuture函數(shù)式異步處理

十、常見同步錯(cuò)誤示例

1. 誤用 String 鎖

// 錯(cuò)誤!字符串常量池導(dǎo)致意外共享鎖
synchronized("LOCK") {
    // ...
}

2. 同步方法調(diào)用非同步方法

class Account {
    private int balance;
    
    public synchronized void transfer(Account target, int amount) {
        this.balance -= amount;
        target.deposit(amount);  // 未同步!可能破壞不變性條件
    }
    
    public void deposit(int amount) {
        balance += amount;
    }
}

3. 對(duì)象逃逸

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(  // 在構(gòu)造完成前發(fā)布this引用
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
    }
    
    void doSomething(Event e) { ... }
}

總結(jié)

Java 線程同步要點(diǎn):

  1. 理解問題本質(zhì):解決共享資源訪問沖突
  2. 選擇合適的工具:從簡(jiǎn)單到復(fù)雜逐步考慮
  3. 遵循最佳實(shí)踐
    • 優(yōu)先使用并發(fā)工具包(java.util.concurrent
    • 避免過度同步
    • 最小化同步范圍
    • 使用線程安全的集合類
  4. 考慮性能影響
    • 無鎖算法 > 樂觀鎖 > 細(xì)粒度鎖 > 粗粒度鎖
    • 讀寫分離提高并發(fā)性
  5. 利用現(xiàn)代特性
    • CompletableFuture 異步編程
    • VarHandle 精細(xì)內(nèi)存控制
    • Virtual Threads(Project Loom)減少同步需求

正確使用同步機(jī)制能構(gòu)建出安全高效的多線程應(yīng)用,而錯(cuò)誤使用可能導(dǎo)致性能問題或難以調(diào)試的并發(fā)缺陷。始終優(yōu)先考慮使用高級(jí)并發(fā)工具而非手動(dòng)實(shí)現(xiàn)同步邏輯。

到此這篇關(guān)于Java中線程同步的文章就介紹到這了,更多相關(guān)java線程同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • httpclient的disableConnectionState方法工作流程

    httpclient的disableConnectionState方法工作流程

    這篇文章主要為大家介紹了httpclient的disableConnectionState方法工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • SpringBoot 異步線程間數(shù)據(jù)傳遞的實(shí)現(xiàn)

    SpringBoot 異步線程間數(shù)據(jù)傳遞的實(shí)現(xiàn)

    本文主要介紹了SpringBoot 異步線程間數(shù)據(jù)傳遞的實(shí)現(xiàn),包括異步線程的基本概念、數(shù)據(jù)傳遞的方式、具體實(shí)現(xiàn)方式等,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Spring實(shí)現(xiàn)HikariCP連接池的示例代碼

    Spring實(shí)現(xiàn)HikariCP連接池的示例代碼

    在SpringBoot 2.0中,我們使用默認(rèn)連接池是HikariCP,本文講一下HikariCP的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-08-08
  • SpringBoot 統(tǒng)一異常處理的實(shí)現(xiàn)示例

    SpringBoot 統(tǒng)一異常處理的實(shí)現(xiàn)示例

    本文主要介紹了SpringBoot 統(tǒng)一異常處理的實(shí)現(xiàn)示例,目的就是在異常發(fā)生時(shí),盡可能地減少破壞,下面就來介紹一下,感興趣的可以了解一下
    2024-07-07
  • java實(shí)現(xiàn)多線程之定時(shí)器任務(wù)

    java實(shí)現(xiàn)多線程之定時(shí)器任務(wù)

    本篇文章主要介紹了java實(shí)現(xiàn)多線程之定時(shí)器任務(wù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • java 方法與數(shù)組基礎(chǔ)使用詳解

    java 方法與數(shù)組基礎(chǔ)使用詳解

    Java語言中的“方法”(Method)在其他語言當(dāng)中也可能被稱為“函數(shù)”(Function),數(shù)組對(duì)于每一門編程語言來說都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語言對(duì)數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java 語言中提供的數(shù)組是用來存儲(chǔ)固定大小的同類型元素
    2022-04-04
  • linux中java獲取路徑的實(shí)例代碼

    linux中java獲取路徑的實(shí)例代碼

    在本篇文章里小編給大家整理的是一篇關(guān)于linux中java獲取路徑的實(shí)例代碼以及相關(guān)知識(shí)點(diǎn),有興趣的朋友們可以學(xué)習(xí)參考下。
    2020-02-02
  • Java設(shè)計(jì)模式之外觀模式示例詳解

    Java設(shè)計(jì)模式之外觀模式示例詳解

    外觀模式為多個(gè)復(fù)雜的子系統(tǒng),提供了一個(gè)一致的界面,使得調(diào)用端只和這個(gè)接口發(fā)生調(diào)用,而無須關(guān)系這個(gè)子系統(tǒng)內(nèi)部的細(xì)節(jié)。本文將通過示例詳細(xì)為大家講解一下外觀模式,需要的可以參考一下
    2022-08-08
  • Java 線程池詳解

    Java 線程池詳解

    本文給大家總結(jié)了java中的線程池的相關(guān)問題,非常的詳細(xì)也很實(shí)用,有需要的小伙伴可以參考下。
    2016-03-03
  • Java集合中的WeakHashMap、IdentityHashMap、EnumMap詳解

    Java集合中的WeakHashMap、IdentityHashMap、EnumMap詳解

    這篇文章主要介紹了Java集合中的WeakHashMap、IdentityHashMap、EnumMap詳解,HashMap的key保留了對(duì)實(shí)際對(duì)象的強(qiáng)引用,這意味著只要HashMap對(duì)象不被銷毀,還HashMap的所有key所引用的對(duì)象就不會(huì)被垃圾回收,需要的朋友可以參考下
    2023-09-09

最新評(píng)論