自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java的ConcurrentHashMap是使用的分段鎖?

開發(fā) 前端
SegmentedCounter類有一個(gè)counters數(shù)組和一個(gè)locks數(shù)組。每個(gè)計(jì)數(shù)器都有一個(gè)與之對(duì)應(yīng)的鎖,這使得線程可以獨(dú)立地更新不同的計(jì)數(shù)器,而不會(huì)相互干擾。當(dāng)然,這個(gè)簡(jiǎn)單的例子并沒有考慮一些高級(jí)的并發(fā)問題,比如鎖的粒度選擇、鎖爭(zhēng)用和公平性等問題。

了不起在前兩天的時(shí)候給大家講述了關(guān)于這個(gè) Java 的公平鎖,非公平鎖,共享鎖,獨(dú)占鎖,樂觀鎖,悲觀鎖,遞歸鎖,讀寫鎖,今天我們就再來了解一下其他的鎖,比如,輕量級(jí)鎖,重量級(jí)鎖,偏向鎖,以及分段鎖。

輕量級(jí)鎖

Java的輕量級(jí)鎖(Lightweight Locking)是Java虛擬機(jī)(JVM)中的一種優(yōu)化機(jī)制,用于減少多線程競(jìng)爭(zhēng)時(shí)的性能開銷。在多線程環(huán)境中,當(dāng)多個(gè)線程嘗試同時(shí)訪問共享資源時(shí),通常需要某種形式的同步以防止數(shù)據(jù)不一致。Java提供了多種同步機(jī)制,如synchronized關(guān)鍵字和ReentrantLock,但在高并發(fā)場(chǎng)景下,這些機(jī)制可能導(dǎo)致性能瓶頸。

輕量級(jí)鎖是JVM中的一種鎖策略,它在沒有多線程競(jìng)爭(zhēng)的情況下提供了較低的開銷,同時(shí)在競(jìng)爭(zhēng)變得激烈時(shí)能夠自動(dòng)升級(jí)到更重量級(jí)的鎖。這種策略的目標(biāo)是在不需要時(shí)避免昂貴的線程阻塞操作。

不過這種鎖并不是通過Java語(yǔ)言直接暴露給開發(fā)者的API,而是JVM在運(yùn)行時(shí)根據(jù)需要自動(dòng)應(yīng)用的。因此,我們不能直接通過Java代碼來實(shí)現(xiàn)一個(gè)輕量級(jí)鎖。

但是我們可以使用Java提供的synchronized關(guān)鍵字或java.util.concurrent.locks.Lock接口(及其實(shí)現(xiàn)類,如ReentrantLock)來創(chuàng)建同步代碼塊或方法,這些同步機(jī)制在底層可能會(huì)被JVM優(yōu)化為使用輕量級(jí)鎖。

示例代碼:

public class LightweightLockExample {  
  
    private Object lock = new Object();  
    private int sharedData;  
  
    public void incrementSharedData() {  
        synchronized (lock) {  
            sharedData++;  
        }  
    }  
  
    public int getSharedData() {  
        synchronized (lock) {  
            return sharedData;  
        }  
    }  
  
    public static void main(String[] args) {  
        LightweightLockExample example = new LightweightLockExample();  
  
        // 使用多個(gè)線程來訪問共享數(shù)據(jù)  
        for (int i = 0; i < 10; i++) {  
            new Thread(() -> {  
                for (int j = 0; j < 1000; j++) {  
                    example.incrementSharedData();  
                }  
            }).start();  
        }  
  
        // 等待所有線程執(zhí)行完畢  
        try {  
            Thread.sleep(2000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
  
        // 輸出共享數(shù)據(jù)的最終值  
        System.out.println("Final shared data value: " + example.getSharedData());  
    }  
}

這個(gè)示例中的同步塊在JVM內(nèi)部可能會(huì)使用輕量級(jí)鎖(具體是否使用取決于JVM的實(shí)現(xiàn)和運(yùn)行時(shí)環(huán)境)

在這個(gè)例子中,我們有一個(gè)sharedData變量,多個(gè)線程可能會(huì)同時(shí)訪問它。我們使用synchronized塊來確保每次只有一個(gè)線程能夠修改sharedData。在JVM內(nèi)部,這些synchronized塊可能會(huì)使用輕量級(jí)鎖來優(yōu)化同步性能。

請(qǐng)注意,這個(gè)例子只是為了演示如何使用synchronized關(guān)鍵字,并不能保證JVM一定會(huì)使用輕量級(jí)鎖。實(shí)際上,JVM可能會(huì)根據(jù)運(yùn)行時(shí)的情況選擇使用偏向鎖、輕量級(jí)鎖或重量級(jí)鎖。

重量級(jí)鎖

在Java中,重量級(jí)鎖(Heavyweight Locking)是相對(duì)于輕量級(jí)鎖而言的,它涉及到線程阻塞和操作系統(tǒng)級(jí)別的線程調(diào)度。當(dāng)輕量級(jí)鎖或偏向鎖不足以解決線程間的競(jìng)爭(zhēng)時(shí),JVM會(huì)升級(jí)鎖為重量級(jí)鎖。

重量級(jí)鎖通常是通過操作系統(tǒng)提供的互斥原語(yǔ)(如互斥量、信號(hào)量等)來實(shí)現(xiàn)的。當(dāng)一個(gè)線程嘗試獲取已經(jīng)被其他線程持有的重量級(jí)鎖時(shí),它會(huì)被阻塞(即掛起),直到持有鎖的線程釋放該鎖。在阻塞期間,線程不會(huì)消耗CPU資源,但會(huì)導(dǎo)致上下文切換的開銷,因?yàn)椴僮飨到y(tǒng)需要保存和恢復(fù)線程的上下文信息。

在Java中,synchronized關(guān)鍵字和java.util.concurrent.locks.ReentrantLock都可以導(dǎo)致重量級(jí)鎖的使用,尤其是在高并發(fā)和激烈競(jìng)爭(zhēng)的場(chǎng)景下。

我們來看看使用synchronized可能會(huì)涉及到重量級(jí)鎖的代碼:

public class HeavyweightLockExample {  
  
    private final Object lock = new Object();  
    private int counter;  
  
    public void increment() {  
        synchronized (lock) {  
            counter++;  
        }  
    }  
  
    public int getCounter() {  
        synchronized (lock) {  
            return counter;  
        }  
    }  
  
    public static void main(String[] args) {  
        HeavyweightLockExample example = new HeavyweightLockExample();  
  
        // 創(chuàng)建多個(gè)線程同時(shí)訪問共享資源  
        for (int i = 0; i < 10; i++) {  
            new Thread(() -> {  
                for (int j = 0; j < 10000; j++) {  
                    example.increment();  
                }  
            }).start();  
        }  
  
        // 等待所有線程完成  
        try {  
            Thread.sleep(2000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
  
        // 輸出計(jì)數(shù)器的值  
        System.out.println("Final counter value: " + example.getCounter());  
    }  
}

在這個(gè)示例中,多個(gè)線程同時(shí)訪問counter變量,并使用synchronized塊來確保每次只有一個(gè)線程能夠修改它。如果線程間的競(jìng)爭(zhēng)非常激烈,JVM可能會(huì)將synchronized塊內(nèi)部的鎖升級(jí)為重量級(jí)鎖。

我們說的是可能哈,畢竟內(nèi)部操作還是由 JVM 具體來操控的。

我們?cè)賮砜纯催@個(gè)ReentrantLock來實(shí)現(xiàn):

import java.util.concurrent.locks.ReentrantLock;  
  
public class ReentrantLockExample {  
  
    private final ReentrantLock lock = new ReentrantLock();  
    private int counter;  
  
    public void increment() {  
        lock.lock(); // 獲取鎖  
        try {  
            counter++;  
        } finally {  
            lock.unlock(); // 釋放鎖  
        }  
    }  
  
    public int getCounter() {  
        return counter;  
    }  
  
    public static void main(String[] args) {  
        // 類似上面的示例,創(chuàng)建線程并訪問共享資源  
    }  
}

在這個(gè)示例中,ReentrantLock被用來同步對(duì)counter變量的訪問。如果鎖競(jìng)爭(zhēng)激烈,ReentrantLock內(nèi)部可能會(huì)使用重量級(jí)鎖。

需要注意的是,重量級(jí)鎖的使用會(huì)帶來較大的性能開銷,因此在設(shè)計(jì)并發(fā)系統(tǒng)時(shí)應(yīng)盡量通過減少鎖競(jìng)爭(zhēng)、使用更細(xì)粒度的鎖、使用無(wú)鎖數(shù)據(jù)結(jié)構(gòu)等方式來避免重量級(jí)鎖的使用。

偏向鎖

在Java中,偏向鎖(Biased Locking)是Java虛擬機(jī)(JVM)為了提高無(wú)競(jìng)爭(zhēng)情況下的性能而引入的一種鎖優(yōu)化機(jī)制。它的基本思想是,如果一個(gè)線程獲得了鎖,那么鎖就進(jìn)入偏向模式,此時(shí)Mark Word的結(jié)構(gòu)也變?yōu)槠蜴i結(jié)構(gòu),當(dāng)這個(gè)線程再次請(qǐng)求鎖時(shí),無(wú)需再做任何同步操作,即獲取鎖的過程只需要檢查Mark Word的鎖標(biāo)記位為偏向鎖以及當(dāng)前線程ID等于Mark Word的Thread ID即可,這樣就省去了大量有關(guān)鎖申請(qǐng)的操作。

他和輕量級(jí)鎖和重量級(jí)鎖一樣,并不是直接通過Java代碼來控制的,而是由JVM在運(yùn)行時(shí)自動(dòng)進(jìn)行的。因此,你不能直接編寫Java代碼來顯式地使用偏向鎖。不過,你可以編寫一個(gè)使用synchronized關(guān)鍵字的簡(jiǎn)單示例,JVM可能會(huì)自動(dòng)將其優(yōu)化為使用偏向鎖(取決于JVM的實(shí)現(xiàn)和運(yùn)行時(shí)的配置)。

示例代碼:

public class BiasedLockingExample {  
  
    // 這個(gè)對(duì)象用作同步的鎖  
    private final Object lock = new Object();  
      
    // 共享資源  
    private int sharedData;  
  
    // 使用synchronized關(guān)鍵字進(jìn)行同步的方法  
    public synchronized void synchronizedMethod() {  
        sharedData++;  
    }  
  
    // 使用對(duì)象鎖進(jìn)行同步的方法  
    public void lockedMethod() {  
        synchronized (lock) {  
            sharedData += 2;  
        }  
    }  
  
    public static void main(String[] args) throws InterruptedException {  
        // 創(chuàng)建示例對(duì)象  
        BiasedLockingExample example = new BiasedLockingExample();  
  
        // 使用Lambda表達(dá)式和Stream API創(chuàng)建并啟動(dòng)多個(gè)線程  
        IntStream.range(0, 10).forEach(i -> {  
            new Thread(() -> {  
                // 每個(gè)線程多次調(diào)用同步方法  
                for (int j = 0; j < 10000; j++) {  
                    example.synchronizedMethod();  
                    example.lockedMethod();  
                }  
            }).start();  
        });  
  
        // 讓主線程睡眠一段時(shí)間,等待其他線程執(zhí)行完畢  
        Thread.sleep(2000);  
  
        // 輸出共享數(shù)據(jù)的最終值  
        System.out.println("Final sharedData value: " + example.sharedData);  
    }  
}

在這個(gè)示例中,我們有一個(gè)BiasedLockingExample類,它有兩個(gè)同步方法:synchronizedMethod和lockedMethod。synchronizedMethod是一個(gè)實(shí)例同步方法,它隱式地使用this作為鎖對(duì)象。lockedMethod是一個(gè)使用顯式對(duì)象鎖的方法,它使用lock對(duì)象作為鎖。

當(dāng)多個(gè)線程調(diào)用這些方法時(shí),JVM可能會(huì)觀察到只有一個(gè)線程在反復(fù)獲取同一個(gè)鎖,并且沒有其他線程競(jìng)爭(zhēng)該鎖。在這種情況下,JVM可能會(huì)將鎖偏向到這個(gè)線程,以減少獲取和釋放鎖的開銷。

然而,請(qǐng)注意以下幾點(diǎn):

  • 偏向鎖的使用是由JVM動(dòng)態(tài)決定的,你不能強(qiáng)制JVM使用偏向鎖。
  • 在高并發(fā)環(huán)境下,如果鎖競(jìng)爭(zhēng)激烈,偏向鎖可能會(huì)被撤銷并升級(jí)到更重的鎖狀態(tài),如輕量級(jí)鎖或重量級(jí)鎖。
  • 偏向鎖適用于鎖被同一個(gè)線程多次獲取的場(chǎng)景。如果鎖被多個(gè)線程頻繁地爭(zhēng)用,偏向鎖可能不是最優(yōu)的選擇。

由于偏向鎖是透明的優(yōu)化,因此你不需要在代碼中做任何特殊的事情來利用它。只需編寫正常的同步代碼,讓JVM來決定是否應(yīng)用偏向鎖優(yōu)化。

分段鎖

在Java中,"分段鎖"并不是一個(gè)官方的術(shù)語(yǔ),但它通常被用來描述一種并發(fā)控制策略,其中數(shù)據(jù)結(jié)構(gòu)或資源被分成多個(gè)段,并且每個(gè)段都有自己的鎖。這種策略的目的是提高并發(fā)性能,允許多個(gè)線程同時(shí)訪問不同的段,而不會(huì)相互阻塞。

而在 Java 里面的經(jīng)典例子則是ConcurrentHashMap,在早期的ConcurrentHashMap實(shí)現(xiàn)中,內(nèi)部采用了一個(gè)稱為Segment的類來表示哈希表的各個(gè)段,每個(gè)Segment對(duì)象都持有一個(gè)鎖。這種設(shè)計(jì)允許多個(gè)線程同時(shí)讀寫哈希表的不同部分,而不會(huì)產(chǎn)生鎖競(jìng)爭(zhēng),從而提高了并發(fā)性能。

然而,需要注意的是,從Java 8開始,ConcurrentHashMap的內(nèi)部實(shí)現(xiàn)發(fā)生了重大變化。它不再使用Segment,而是采用了一種基于CAS(Compare-and-Swap)操作和Node數(shù)組的新設(shè)計(jì),以及紅黑樹來處理哈希沖突。這種新設(shè)計(jì)提供了更高的并發(fā)性和更好的性能。盡管如此,"分段鎖"這個(gè)概念仍然可以用來描述這種將數(shù)據(jù)結(jié)構(gòu)分成多個(gè)可獨(dú)立鎖定的部分的通用策略。

我們看一個(gè)分段鎖實(shí)現(xiàn)安全計(jì)數(shù)器的代碼:

import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
  
public class SegmentedCounter {  
    private final int size;  
    private final Lock[] locks;  
    private final int[] counters;  
  
    public SegmentedCounter(int size) {  
        this.size = size;  
        this.locks = new Lock[size];  
        this.counters = new int[size];  
        for (int i = 0; i < size; i++) {  
            locks[i] = new ReentrantLock();  
        }  
    }  
  
    public void increment(int index) {  
        locks[index].lock();  
        try {  
            counters[index]++;  
        } finally {  
            locks[index].unlock();  
        }  
    }  
  
    public int getValue(int index) {  
        locks[index].lock();  
        try {  
            return counters[index];  
        } finally {  
            locks[index].unlock();  
        }  
    }  
}

在這個(gè)例子中,SegmentedCounter類有一個(gè)counters數(shù)組和一個(gè)locks數(shù)組。每個(gè)計(jì)數(shù)器都有一個(gè)與之對(duì)應(yīng)的鎖,這使得線程可以獨(dú)立地更新不同的計(jì)數(shù)器,而不會(huì)相互干擾。當(dāng)然,這個(gè)簡(jiǎn)單的例子并沒有考慮一些高級(jí)的并發(fā)問題,比如鎖的粒度選擇、鎖爭(zhēng)用和公平性等問題。在實(shí)際應(yīng)用中,你可能需要根據(jù)具體的需求和性能目標(biāo)來調(diào)整設(shè)計(jì)。

所以,你學(xué)會(huì)了么?

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2023-10-10 08:39:25

Java 7Java 8

2022-01-24 07:01:20

安全多線程版本

2024-10-31 11:16:19

高并發(fā)并發(fā)集JDK

2025-03-27 01:10:00

HashMap分段鎖CAS

2017-12-23 00:00:12

2020-12-28 08:25:08

Java并發(fā)HashMap

2019-01-15 10:37:52

2015-07-08 16:06:15

iOS遞歸鎖

2024-12-30 11:18:09

Java框架HashTable

2024-01-29 01:08:01

悲觀鎖遞歸鎖讀寫鎖

2022-06-15 07:32:35

Lock線程Java

2022-08-09 07:37:40

對(duì)象并發(fā)容器

2015-06-15 10:12:36

Java原理分析

2022-03-14 18:18:11

橫向攻擊網(wǎng)絡(luò)攻擊

2024-02-29 09:44:36

Java工具

2024-05-15 09:23:45

MySQL排他鎖共享鎖

2019-10-17 08:51:00

Java悲觀鎖Monitor

2020-01-16 14:59:32

Java鎖優(yōu)化CAS

2024-04-19 08:05:26

鎖升級(jí)Java虛擬機(jī)

2023-02-02 11:53:44

nolock關(guān)鍵詞SQLserver
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)