最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java鎖機(jī)制詳細(xì)講解與實(shí)戰(zhàn)應(yīng)用

 更新時(shí)間:2025年12月02日 16:43:29   作者:小碼快撩  
本文全面介紹了Java中的鎖機(jī)制,包括synchronized關(guān)鍵字、內(nèi)置鎖、顯示鎖、讀寫鎖、條件變量、樂觀鎖、悲觀鎖、自旋鎖和StampedLock,通過實(shí)際代碼示例,詳細(xì)講解了每種鎖的實(shí)現(xiàn)方法和應(yīng)用場景,感興趣的朋友跟隨小編一起看看吧

引言

在多線程編程中,確保數(shù)據(jù)的并發(fā)訪問安全是至關(guān)重要的。Java作為支持多線程編程的主流語言,提供了多種內(nèi)置和高級(jí)鎖機(jī)制來解決共享資源的競爭問題,從而保證線程間的同步與協(xié)作。本文將全面探討Java中的鎖機(jī)制,從基本概念、類型到具體實(shí)現(xiàn)方法,并結(jié)合實(shí)際應(yīng)用場景進(jìn)行說明。

一、synchronized關(guān)鍵字

 Java中的synchronized關(guān)鍵字是一種內(nèi)置鎖機(jī)制,用于保證多線程環(huán)境下的線程安全。它提供了簡單易用的互斥訪問控制,確保同一時(shí)刻只有一個(gè)線程可以執(zhí)行特定代碼塊。

下面是一個(gè)使用synchronized關(guān)鍵字的示例代碼:

public class SynchronizedExample {
    private int counter;
    public synchronized void increment() {
        counter++;
    }
    public synchronized int getCount() {
        return counter;
    }
}

在上面的示例中,increment() 和 getCount() 方法都使用了 synchronized 關(guān)鍵字。這意味著當(dāng)一個(gè)線程正在執(zhí)行其中一個(gè)方法時(shí),其他線程想要執(zhí)行另一個(gè)方法將被阻塞,直到當(dāng)前線程執(zhí)行完畢并釋放鎖。

synchronized 關(guān)鍵字可以用于以下場景:

  • 修飾實(shí)例方法:如示例中的 increment() 和 getCount() 方法。當(dāng)一個(gè)線程訪問某個(gè)對象的同步方法時(shí),其他線程對該對象的其他同步方法訪問將被阻塞。
  • 修飾靜態(tài)方法:可以使用 synchronized 關(guān)鍵字修飾靜態(tài)方法,以實(shí)現(xiàn)對整個(gè)類的同步訪問。
public class SynchronizedStaticExample {
    private static int counter;
    public static synchronized void increment() {
        counter++;
    }
    public static synchronized int getCount() {
        return counter;
    }
}
  • 修飾代碼塊:可以使用 synchronized 關(guān)鍵字修飾代碼塊,以實(shí)現(xiàn)對特定資源的同步訪問。
public class SynchronizedBlockExample {
    private int counter;
    private Object lock = new Object();
    public void increment() {
        synchronized(lock) {
            counter++;
        }
    }
    public int getCount() {
        synchronized(lock) {
            return counter;
        }
    }
}

在上面的示例中,increment() 和 getCount() 方法內(nèi)部的同步代碼塊使用了同一個(gè)鎖對象 lock。這意味著當(dāng)一個(gè)線程訪問其中一個(gè)同步代碼塊時(shí),其他線程想要訪問另一個(gè)同步代碼塊將被阻塞,直到當(dāng)前線程執(zhí)行完畢并釋放鎖。

二、內(nèi)置鎖(Intrinsic Locks or Monitor Locks)

 Java內(nèi)置鎖(Intrinsic Locks 或 Monitor Locks)是基于JVM實(shí)現(xiàn)的一種同步機(jī)制,每個(gè)Java對象都可以關(guān)聯(lián)一個(gè)內(nèi)置鎖。當(dāng)線程試圖訪問被 synchronized 關(guān)鍵字修飾的方法或代碼塊時(shí),會(huì)嘗試獲取該對象的內(nèi)置鎖,如果成功,則可以執(zhí)行相應(yīng)的臨界區(qū)代碼;如果失?。存i已被其他線程持有),則當(dāng)前線程將進(jìn)入阻塞狀態(tài),等待鎖釋放。

以下是一個(gè)使用Java內(nèi)置鎖的示例代碼:

public class IntrinsicLockExample {
    private int counter = 0;
    // 同步實(shí)例方法,隱式使用 this 對象作為鎖
    public synchronized void increment() {
        counter++;
    }
    // 同步代碼塊,顯式指定鎖對象
    public void incrementWithBlock(Object lock) {
        synchronized (lock) {
            counter++;
        }
    }
    // 獲取當(dāng)前計(jì)數(shù)
    public synchronized int getCount() {
        return counter;
    }
    // 示例類中的靜態(tài)變量和對應(yīng)的同步方法
    private static int staticCounter = 0;
    public static synchronized void incrementStatic() {
        staticCounter++;
    }
}
// 使用示例
public class Main {
    public static void main(String[] args) {
        IntrinsicLockExample example = new IntrinsicLockExample();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Final count: " + example.getCount());  // 輸出結(jié)果應(yīng)為2000
        // 靜態(tài)成員的同步示例
        for (int i = 0; i < 500; i++) {
            IntrinsicLockExample.incrementStatic();
        }
        System.out.println("Final static count: " + IntrinsicLockExample.staticCounter);  // 輸出結(jié)果應(yīng)為500
    }
}

詳細(xì)解釋:

  • 在 increment() 方法中,使用了 synchronized 關(guān)鍵字修飾,這意味著每次只有一個(gè)線程可以執(zhí)行這個(gè)方法,確保了對 counter 變量的并發(fā)訪問安全。
  • incrementWithBlock() 方法展示了如何在代碼塊級(jí)別使用內(nèi)置鎖,通過傳入一個(gè) Object 類型的鎖參數(shù),多個(gè)方法可以共享同一把鎖,達(dá)到同步的目的。
  • getCount() 方法同樣使用了 synchronized,保證了讀取 counter 的線程安全。
  • incrementStatic() 是一個(gè)同步靜態(tài)方法,它使用的是類級(jí)別的內(nèi)置鎖,因此在同一時(shí)刻只能有一個(gè)線程修改 staticCounter 變量。

三、顯示鎖(Lock)

 Java顯示鎖(顯示鎖通常指的是java.util.concurrent.locks.Lock接口及其實(shí)現(xiàn)類)提供了比內(nèi)置鎖(synchronized關(guān)鍵字)更強(qiáng)大和靈活的線程同步機(jī)制。顯示鎖允許程序員更加精確地控制線程的加鎖和解鎖行為,支持中斷請求,以及非阻塞式的嘗試獲取鎖等特性。

以下是使用java.util.concurrent.locks.ReentrantLock作為顯示鎖的一個(gè)示例代碼:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DisplayedLockExample {
    private final Lock lock = new ReentrantLock();
    private int counter;
    public void increment() {
        lock.lock(); // 加鎖
        try {
            counter++;
        } finally {
            lock.unlock(); // 無論何時(shí)都要確保解鎖
        }
    }
    public int getCount() {
        lock.lock(); // 同樣需要加鎖保護(hù)
        try {
            return counter;
        } finally {
            lock.unlock();
        }
    }
    // 顯示鎖還提供了更多的控制方式,比如嘗試獲取鎖,支持中斷等
    public void tryIncrementWithTimeout(int timeout, TimeUnit unit) throws InterruptedException {
        if (lock.tryLock(timeout, unit)) {
            try {
                counter++;
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("未能在規(guī)定時(shí)間內(nèi)獲取到鎖");
        }
    }
}
// 使用示例
public class Main {
    public static void main(String[] args) {
        DisplayedLockExample example = new DisplayedLockExample();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Final count: " + example.getCount());  // 輸出結(jié)果應(yīng)為2000
    }
}

詳細(xì)解釋:

  • DisplayedLockExample 類中定義了一個(gè) ReentrantLock 對象作為顯示鎖。
  • increment() 和 getCount() 方法在修改或讀取 counter 變量時(shí),均首先獲取鎖,然后在 finally 語句塊中確保無論如何都能釋放鎖,這是一種最佳實(shí)踐,確保即使在異常情況下也能正確釋放鎖。
  • tryIncrementWithTimeout() 方法演示了顯示鎖的超時(shí)獲取功能,它嘗試在指定時(shí)間內(nèi)獲取鎖,若超過設(shè)定時(shí)間仍無法獲取,則不再等待并繼續(xù)執(zhí)行后續(xù)邏輯。

顯示鎖相比內(nèi)置鎖的優(yōu)勢:

  1. 可以嘗試非阻塞地獲取鎖,比如 tryLock() 和 tryLock(long timeout, TimeUnit unit) 方法。
  2. 支持中斷,線程在等待鎖時(shí)可以響應(yīng)中斷請求,這對于那些需要取消長時(shí)間等待的任務(wù)非常有用。
  3. 可以實(shí)現(xiàn)公平鎖策略,即按照線程請求鎖的順序來分配鎖,避免“饑餓”現(xiàn)象。
  4. 提供了鎖的監(jiān)聽和喚醒機(jī)制,可通過 Condition 對象實(shí)現(xiàn)更復(fù)雜的同步結(jié)構(gòu)

四、讀寫鎖(Read-Write Locks)

 Java的讀寫鎖(Read-Write Locks)是一種特殊的鎖機(jī)制,它允許多個(gè)讀取者同時(shí)訪問共享資源,但在寫入者訪問時(shí)會(huì)排斥所有讀取者和其他寫入者。這使得在讀多寫少的情況下,系統(tǒng)的并發(fā)性能得到顯著提升。Java中實(shí)現(xiàn)讀寫鎖的主要類是java.util.concurrent.locks.ReadWriteLock,以及它的標(biāo)準(zhǔn)實(shí)現(xiàn)java.util.concurrent.locks.ReentrantReadWriteLock。

以下是一個(gè)使用ReentrantReadWriteLock的示例代碼及其詳細(xì)解釋:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockExample {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();
    private int sharedResource;
    public void read() {
        readLock.lock(); // 獲取讀鎖
        try {
            // 多個(gè)線程可以同時(shí)在這里讀取數(shù)據(jù)
            System.out.println("Reading the resource: " + sharedResource);
        } finally {
            readLock.unlock(); // 釋放讀鎖
        }
    }
    public void update() {
        writeLock.lock(); // 獲取寫鎖
        try {
            // 當(dāng)有線程在執(zhí)行這里的寫操作時(shí),其他所有讀寫線程都會(huì)被阻塞
            sharedResource++;
            System.out.println("Updated the resource to: " + sharedResource);
        } finally {
            writeLock.unlock(); // 釋放寫鎖
        }
    }
    // 使用示例
    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();
        ExecutorService executor = Executors.newFixedThreadPool(10);
        // 創(chuàng)建大量讀取任務(wù)
        for (int i = 0; i < 20; i++) {
            executor.submit(() -> example.read());
        }
        // 創(chuàng)建少量寫入任務(wù)
        for (int i = 0; i < 5; i++) {
            executor.submit(() -> example.update());
        }
        // 關(guān)閉線程池
        executor.shutdown();
    }
}

詳細(xì)解釋:

  • ReadWriteLockExample 類中定義了一個(gè) ReentrantReadWriteLock 對象,并從中提取出讀鎖 readLock 和寫鎖 writeLock。
  • read() 方法獲取讀鎖后讀取共享資源 sharedResource,此時(shí)如果有多個(gè)線程同時(shí)調(diào)用 read() 方法,它們可以同時(shí)執(zhí)行,因?yàn)樽x鎖是共享的。
  • update() 方法獲取寫鎖后更新 sharedResource,在執(zhí)行寫操作時(shí),所有其他嘗試獲取讀鎖或?qū)戞i的線程都會(huì)被阻塞,直到寫操作完成并釋放寫鎖為止。
  • 在主方法中,我們創(chuàng)建了一個(gè)線程池,提交了大量的讀任務(wù)和少量的寫任務(wù),模擬了讀多寫少的場景,這時(shí)讀寫鎖可以有效提高系統(tǒng)并發(fā)性能。

五、條件變量(Condition Objects)

 在Java中,條件變量是通過java.util.concurrent.locks.Condition接口實(shí)現(xiàn)的,它與鎖(如ReentrantLock)一起使用,允許線程等待滿足特定條件時(shí)被喚醒。下面是一個(gè)使用Condition對象的示例代碼及詳細(xì)解釋:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionVariableExample {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    // 共享資源,模擬隊(duì)列為空的情況
    private boolean isEmpty = true;
    public void produce() {
        lock.lock();
        try {
            // 當(dāng)隊(duì)列為空時(shí),生產(chǎn)者線程等待condition被signal
            while (!isEmpty) {
                condition.await();  // 線程在此處釋放鎖并進(jìn)入等待狀態(tài)
            }
            // 生產(chǎn)商品邏輯...
            System.out.println("Produced an item, queue is no longer empty.");
            isEmpty = false;  // 更新條件
            // 喚醒所有等待此condition的消費(fèi)者線程
            condition.signalAll();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();  // 不論如何都要確保解鎖
        }
    }
    public void consume() {
        lock.lock();
        try {
            // 當(dāng)隊(duì)列非空時(shí),消費(fèi)者線程等待condition被signal
            while (isEmpty) {
                condition.await();  // 線程在此處釋放鎖并進(jìn)入等待狀態(tài)
            }
            // 消費(fèi)商品邏輯...
            System.out.println("Consumed an item, queue is now empty.");
            isEmpty = true;  // 更新條件
            // 喚醒所有等待此condition的生產(chǎn)者線程
            condition.signalAll();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();  // 不論如何都要確保解鎖
        }
    }
    // 使用示例
    public static void main(String[] args) throws InterruptedException {
        ConditionVariableExample example = new ConditionVariableExample();
        Thread producer = new Thread(example::produce);
        Thread consumer = new Thread(example::consume);
        producer.start();
        consumer.start();
        // 確保生產(chǎn)者先啟動(dòng)并改變條件
        Thread.sleep(100);
        example.produce();  // 手動(dòng)調(diào)用一次生產(chǎn)方法,以初始化條件變化
        producer.join();
        consumer.join();
    }
}

詳細(xì)解釋:

  • ConditionVariableExample 類中定義了一個(gè) ReentrantLock 對象和從該鎖對象創(chuàng)建的一個(gè) Condition 對象。
  • 在 produce() 方法中,當(dāng)共享資源(這里用 isEmpty 標(biāo)記隊(duì)列是否為空)為真(即隊(duì)列為空)時(shí),生產(chǎn)者線程調(diào)用 condition.await() 方法進(jìn)入等待狀態(tài),并釋放鎖。這樣,其他線程可以修改 isEmpty 的值。
  • 當(dāng) consume() 方法中的消費(fèi)者線程檢測到 isEmpty 為假(即隊(duì)列非空),則消費(fèi)者線程調(diào)用 condition.await() 進(jìn)入等待狀態(tài)。
  • 當(dāng)條件發(fā)生變化時(shí),比如生產(chǎn)者生產(chǎn)了物品使得隊(duì)列不再為空,則會(huì)調(diào)用 condition.signalAll() 來喚醒所有等待該條件的線程。
  • 注意,每個(gè)方法都在 try-finally 結(jié)構(gòu)中管理鎖的加鎖和解鎖操作,確保即使在異常情況下也能正確釋放鎖。

六、樂觀鎖(Optimistic Locking)

 樂觀鎖在Java中的實(shí)現(xiàn)通常依賴于原子變量類(如java.util.concurrent.atomic包下的類)或數(shù)據(jù)庫事務(wù)中的版本號(hào)機(jī)制。樂觀鎖的假設(shè)是大多數(shù)情況下數(shù)據(jù)不會(huì)發(fā)生沖突,因此在修改數(shù)據(jù)前并不加鎖,而是在更新時(shí)檢查在此期間是否有其他線程修改過該數(shù)據(jù)。如果發(fā)現(xiàn)數(shù)據(jù)未被修改,則執(zhí)行更新操作;否則則需要重新讀取、驗(yàn)證并嘗試更新。

以下是一個(gè)使用AtomicInteger作為樂觀鎖機(jī)制實(shí)現(xiàn)的簡單示例:

import java.util.concurrent.atomic.AtomicInteger;
public class OptimisticLockingExample {
    private AtomicInteger counter = new AtomicInteger(0);
    public void increment() {
        // 讀取當(dāng)前值
        int currentValue;
        do {
            // 獲取一個(gè)可能過時(shí)的值
            currentValue = counter.get();
            // 檢查在此期間是否已經(jīng)被其他線程修改過
        } while (!counter.compareAndSet(currentValue, currentValue + 1));  // 如果當(dāng)前值未變,則更新為原值+1
        System.out.println("Counter incremented to: " + counter.get());
    }
    public static void main(String[] args) {
        OptimisticLockingExample example = new OptimisticLockingExample();
        Thread thread1 = new Thread(example::increment);
        Thread thread2 = new Thread(example::increment);
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

詳細(xì)解釋:

  • 在這個(gè)例子中,我們使用了AtomicInteger來模擬一個(gè)計(jì)數(shù)器,它具有原子性的get()和compareAndSet()方法。
  • compareAndSet()方法(也稱為CAS操作)嘗試將當(dāng)前值與預(yù)期值進(jìn)行比較,如果當(dāng)前值等于預(yù)期值,則以原子方式更新為新值。這里的預(yù)期值就是我們在循環(huán)開始時(shí)獲取到的currentValue。
  • 當(dāng)多個(gè)線程同時(shí)調(diào)用increment()方法時(shí),它們都會(huì)嘗試更新計(jì)數(shù)器。如果在某一線程嘗試更新之前,計(jì)數(shù)器已被其他線程更新,則其compareAndSet()會(huì)失敗,并且該線程將繼續(xù)下一次循環(huán),再次獲取最新的currentValue并嘗試更新。
  • 這樣,在并發(fā)環(huán)境下,樂觀鎖通過不斷的重試確保了最終只有一個(gè)線程成功地進(jìn)行了原子性更新,從而實(shí)現(xiàn)了線程安全的計(jì)數(shù)操作。

七、悲觀鎖(Pessimistic Locking)

 悲觀鎖在Java中通常表現(xiàn)為獲取到一個(gè)鎖后,其他線程嘗試訪問該資源時(shí)會(huì)立即被阻塞,直到持有鎖的線程釋放鎖。最直接的例子就是使用synchronized關(guān)鍵字修飾的方法或代碼塊。但為了更好地說明數(shù)據(jù)庫層面的悲觀鎖實(shí)現(xiàn),這里提供一個(gè)基于JDBC和Hibernate的示例:

JDBC示例(通過SQL的SELECT ... FOR UPDATE實(shí)現(xiàn)悲觀鎖):

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class PessimisticLockingExampleJDBC {
    private static final String URL = "jdbc:mysql://localhost:3306/mydb";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    public void updateDataWithPessimisticLock(int id) {
        try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {
            connection.setAutoCommit(false); // 關(guān)閉自動(dòng)提交,開始事務(wù)
            // 使用FOR UPDATE來獲取悲觀鎖
            String sql = "SELECT * FROM my_table WHERE id = ? FOR UPDATE";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, id);
            preparedStatement.execute();
            // 假設(shè)我們從查詢結(jié)果中獲取了數(shù)據(jù),并準(zhǔn)備更新它...
            // 更新操作
            String updateSql = "UPDATE my_table SET column = ? WHERE id = ?";
            preparedStatement = connection.prepareStatement(updateSql);
            preparedStatement.setString(1, "new_value");
            preparedStatement.setInt(2, id);
            preparedStatement.executeUpdate();
            connection.commit();  // 提交事務(wù),釋放鎖
        } catch (SQLException e) {
            // 處理異常并回滾事務(wù)
            try {
                if (connection != null) {
                    connection.rollback();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}

Hibernate示例(通過Session的鎖定方法實(shí)現(xiàn)悲觀鎖):

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class PessimisticLockingExampleHibernate {
    private SessionFactory sessionFactory;
    public PessimisticLockingExampleHibernate() {
        Configuration configuration = new Configuration().configure();
        sessionFactory = configuration.buildSessionFactory();
    }
    public void updateDataWithPessimisticLock(Integer id) {
        try (Session session = sessionFactory.openSession()) {
            // 開始事務(wù)
            session.beginTransaction();
            // 加載實(shí)體并顯式地請求悲觀鎖
            MyEntity entity = session.get(MyEntity.class, id, LockMode.PESSIMISTIC_WRITE);
            // 假設(shè)我們在這里修改了entity的屬性值...
            entity.setProperty("new_value");
            // 提交事務(wù),同時(shí)釋放鎖
            session.getTransaction().commit();
        } catch (Exception e) {
            // 如果發(fā)生異常,則回滾事務(wù)
            if (session != null && session.getTransaction() != null && session.getTransaction().isActive()) {
                session.getTransaction().rollback();
            }
            e.printStackTrace();
        }
    }
}
@Entity
@Table(name = "my_table")
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    // 其他屬性及getter、setter省略...
}

詳細(xì)解釋:

  • 在JDBC示例中,通過設(shè)置事務(wù)并執(zhí)行SELECT ... FOR UPDATE語句,在讀取記錄的同時(shí)獲得了對該記錄的悲觀鎖,使得其他事務(wù)無法修改這條記錄,直至當(dāng)前事務(wù)結(jié)束。
  • 在Hibernate示例中,通過session.get()方法加載實(shí)體對象時(shí)指定了LockMode.PESSIMISTIC_WRITE模式,這樣在獲取實(shí)體時(shí)即獲得了一把悲觀寫鎖,阻止其他事務(wù)對同一實(shí)體進(jìn)行并發(fā)修改。

八、自旋鎖(Spin Locks)

 自旋鎖在Java中主要用于解決線程間短時(shí)間的同步問題,尤其適用于等待時(shí)間極短并且CPU資源相對充足的場景。在Java中并沒有直接提供名為“自旋鎖”的API,但是可以通過循環(huán)和volatile關(guān)鍵字模擬實(shí)現(xiàn)自旋鎖的行為。以下是一個(gè)簡單的自旋鎖示例:

public class SpinLock {
    private volatile boolean isLocked = false;
    public void lock() {
        while (true) {
            if (!isLocked) { // 當(dāng)鎖未被占用時(shí)
                if (compareAndSet(false, true)) { // 使用CAS操作嘗試獲取鎖
                    break; // 成功獲取鎖后退出自旋
                }
            }
            // 鎖被占用時(shí),繼續(xù)循環(huán)(自旋)
        }
    }
    public void unlock() {
        isLocked = false; // 釋放鎖
    }
    // 使用AtomicBoolean或Unsafe等工具類提供的原子操作來實(shí)現(xiàn)compareAndSet
    private boolean compareAndSet(boolean expect, boolean update) {
        return java.util.concurrent.atomic.AtomicBoolean.compareAndSet(this.isLocked, expect, update);
    }
    // 示例用法
    public static void main(String[] args) {
        final SpinLock spinLock = new SpinLock();
        Thread t1 = new Thread(() -> {
            spinLock.lock();
            try {
                System.out.println("Thread 1 acquired the lock");
                Thread.sleep(1000); // 模擬執(zhí)行耗時(shí)任務(wù)
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                spinLock.unlock();
            }
        });
        Thread t2 = new Thread(() -> {
            spinLock.lock();
            try {
                System.out.println("Thread 2 acquired the lock");
            } finally {
                spinLock.unlock();
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

詳細(xì)解釋:

  • 在上述代碼中,我們創(chuàng)建了一個(gè)名為SpinLock的類,其中包含一個(gè)volatile布爾變量isLocked,用于表示鎖的狀態(tài)。
  • lock()方法通過不斷地檢查并試圖更新isLocked變量來實(shí)現(xiàn)自旋。當(dāng)isLocked為false時(shí),使用compareAndSet()原子操作將其設(shè)置為true,如果成功則說明當(dāng)前線程獲得了鎖,并跳出循環(huán)。
  • unlock()方法將isLocked設(shè)置為false,以釋放鎖。
  • compareAndSet()方法利用Java的原子性操作(這里假設(shè)使用了AtomicBoolean)確保對isLocked變量的修改是原子性的,這可以避免多線程環(huán)境下數(shù)據(jù)競爭的問題。

九、StampedLock

Java中的StampedLock是Java 8引入的一個(gè)高性能的并發(fā)工具類,它提供了更靈活的讀寫鎖機(jī)制,包括悲觀讀鎖、樂觀讀鎖和寫鎖。每個(gè)鎖操作都會(huì)返回一個(gè)戳記(stamp),后續(xù)的操作可以通過這個(gè)戳記來驗(yàn)證或釋放鎖。

以下是一個(gè)使用StampedLock實(shí)現(xiàn)讀寫鎖的示例代碼及詳細(xì)解釋:

import java.util.concurrent.locks.StampedLock;
public class StampedLockExample {
    private final StampedLock lock = new StampedLock();
    // 共享資源
    private int sharedResource;
    public void read() {
        long stamp = lock.readLock(); // 獲取悲觀讀鎖
        try {
            // 在此塊中可以安全地讀取sharedResource
            System.out.println("Reading the resource: " + sharedResource);
        } finally {
            lock.unlockRead(stamp); // 釋放讀鎖
        }
    }
    public void optimisticRead() {
        long stamp = lock.tryOptimisticRead(); // 嘗試獲取樂觀讀鎖
        int localCopy = sharedResource;
        if (lock.validate(stamp)) { // 驗(yàn)證在獲取戳記后,數(shù)據(jù)是否被其他線程修改過
            // 如果沒有被修改,則可以安全地使用localCopy
            System.out.println("Optimistically reading the resource: " + localCopy);
        } else {
            // 如果有被修改,需要升級(jí)到悲觀讀鎖或者重新讀取
            long newStamp = lock.readLock();
            try {
                // 現(xiàn)在可以安全地再次讀取資源
                localCopy = sharedResource;
                System.out.println("Upgraded to悲觀讀鎖, reading the resource: " + localCopy);
            } finally {
                lock.unlockRead(newStamp); // 釋放悲觀讀鎖
            }
        }
    }
    public void write(int newValue) {
        long stamp = lock.writeLock(); // 獲取寫鎖
        try {
            // 在此塊中可以安全地更新sharedResource
            sharedResource = newValue;
            System.out.println("Updated the resource to: " + sharedResource);
        } finally {
            lock.unlockWrite(stamp); // 釋放寫鎖
        }
    }
    // 使用示例
    public static void main(String[] args) {
        StampedLockExample example = new StampedLockExample();
        // 創(chuàng)建并啟動(dòng)多個(gè)讀取者和寫入者線程...
    }
}

詳細(xì)解釋:

1.StampedLock提供三種模式的鎖:

  • 悲觀讀鎖:通過readLock()方法獲取,類似于ReentrantReadWriteLock中的讀鎖,當(dāng)有寫鎖持有時(shí),讀鎖會(huì)阻塞。
  • 樂觀讀鎖:通過tryOptimisticRead()方法嘗試獲取,該方法立即返回,不會(huì)阻塞,但必須在之后調(diào)用validate(long stamp)方法確認(rèn)讀取期間是否有寫鎖發(fā)生改變,如果數(shù)據(jù)被修改則需升級(jí)為悲觀讀鎖。
  • 寫鎖:通過writeLock()方法獲取,與ReentrantReadWriteLock類似,獨(dú)占鎖,不允許任何其他讀或?qū)戞i同時(shí)存在。

2.示例中read()方法展示了如何使用悲觀讀鎖進(jìn)行讀操作,在讀取期間阻止寫操作。

3.optimisticRead()方法首先嘗試樂觀讀鎖,然后檢查戳記的有效性。若數(shù)據(jù)未被更改,則可以直接使用本地緩存的值;否則,為了確保讀取到最新數(shù)據(jù),需要升級(jí)到悲觀讀鎖。

4.write()方法展示了如何使用寫鎖執(zhí)行寫操作,在寫入期間阻止所有其他讀寫操作。

總結(jié)

深入理解和熟練掌握J(rèn)ava中的鎖機(jī)制是構(gòu)建高效、穩(wěn)定多線程程序的關(guān)鍵所在。開發(fā)者應(yīng)依據(jù)具體的并發(fā)場景,權(quán)衡鎖的開銷與安全性,合理選擇并應(yīng)用合適的鎖實(shí)現(xiàn)。

到此這篇關(guān)于Java鎖機(jī)制詳細(xì)講解與實(shí)戰(zhàn)應(yīng)用的文章就介紹到這了,更多相關(guān)Java鎖機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java對象轉(zhuǎn)型實(shí)例分析

    java對象轉(zhuǎn)型實(shí)例分析

    這篇文章主要介紹了java對象轉(zhuǎn)型的概念及用法,并以實(shí)例形式進(jìn)行了較為詳細(xì)的介紹,需要的朋友可以參考下
    2014-10-10
  • 深度對比與解析SpringBoot中的application.properties與application.yml

    深度對比與解析SpringBoot中的application.properties與application.yml

    在Springboot項(xiàng)目中,使用.properties和.yml配置是等效的,均可以正常識(shí)別并使用,本文將為大家深入對比與解析一下二者的使用與區(qū)別,希望對大家有一定的幫助
    2025-04-04
  • 帶你了解10道java入門面試題

    帶你了解10道java入門面試題

    面試題相信大家都不陌生,想要一個(gè)好的工作面試題必不可少的,下面和小編一起來學(xué)習(xí)與了解Java當(dāng)中有有些什么面試題吧,希望能給你帶來幫助
    2021-08-08
  • java LinkedList的實(shí)例詳解

    java LinkedList的實(shí)例詳解

    這篇文章主要介紹了java LinkedList的實(shí)例詳解的相關(guān)資料,通過本文希望大家能徹底了解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • java數(shù)據(jù)結(jié)構(gòu)之樹基本概念解析及代碼示例

    java數(shù)據(jù)結(jié)構(gòu)之樹基本概念解析及代碼示例

    這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)之樹基本概念解析及代碼示例,介紹了樹的定義,基本術(shù)語,主要操作及實(shí)現(xiàn)等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可了解下。
    2017-11-11
  • MapStruct實(shí)體轉(zhuǎn)換及List轉(zhuǎn)換的方法講解

    MapStruct實(shí)體轉(zhuǎn)換及List轉(zhuǎn)換的方法講解

    今天小編就為大家分享一篇關(guān)于MapStruct實(shí)體轉(zhuǎn)換及List轉(zhuǎn)換的方法講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • swing中Tree與滾動(dòng)條用法實(shí)例分析

    swing中Tree與滾動(dòng)條用法實(shí)例分析

    這篇文章主要介紹了swing中Tree與滾動(dòng)條用法,以實(shí)例形式分析了java基于swing實(shí)現(xiàn)圖形界面的使用技巧,需要的朋友可以參考下
    2015-09-09
  • Java超詳細(xì)介紹抽象類與接口的使用

    Java超詳細(xì)介紹抽象類與接口的使用

    在類中沒有包含足夠的信息來描繪一個(gè)具體的對象,這樣的類稱為抽象類,接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類和接口,感興趣的朋友一起看看吧
    2022-05-05
  • Java Web 登錄頁面的實(shí)現(xiàn)代碼實(shí)例

    Java Web 登錄頁面的實(shí)現(xiàn)代碼實(shí)例

    這篇文章主要介紹了Java Web 登錄頁面的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 通過實(shí)例學(xué)習(xí)Either 樹和模式匹配

    通過實(shí)例學(xué)習(xí)Either 樹和模式匹配

    這篇文章主要介紹了通過實(shí)例學(xué)習(xí)Either 樹和模式匹配,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06

最新評論

东明县| 准格尔旗| 通河县| 琼中| 綦江县| 祁阳县| 长沙县| 平阴县| 仁寿县| 寻乌县| 吴旗县| 常山县| 科技| 纳雍县| 遂川县| 德令哈市| 隆昌县| 东平县| 秀山| 富宁县| 武乡县| 巴南区| 惠水县| 连平县| 榆树市| 上犹县| 枣强县| 启东市| 石台县| 芮城县| 海淀区| 唐山市| 宝鸡市| 中方县| 阿鲁科尔沁旗| 安西县| 仙桃市| 云安县| 富民县| 通州区| 临澧县|