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

JAVA中Synchronized能否加鎖字符串詳解

 更新時間:2025年07月04日 10:17:02   作者:拾荒的小海螺  
在Java中Synchronized可以鎖任何對象,包括字符串,但由于字符串常量在字符串池中是共享的,所以如果多個線程使用相同的字符串作為鎖對象,可能會導(dǎo)致意外的行為,這篇文章主要介紹了JAVA中Synchronized能否加鎖字符串的相關(guān)資料,需要的朋友可以參考下

1、簡述

在 Java 開發(fā)中,synchronized 是一種常見的同步機制,用于保證線程安全。但是你有沒有思考過這樣一個問題:

“synchronized 可以給字符串(String)加鎖嗎?”

答案是:可以,但你應(yīng)該非常小心。

本文將深入剖析這個問題,講清楚背后的機制、風險,并給出實際建議。

2、synchronized 本質(zhì)上加的是什么鎖?

synchronized 實際上加的是對象鎖,也叫監(jiān)視器鎖(monitor lock)。也就是說:

synchronized (obj) {
    // 臨界區(qū)
}

這段代碼表示:只有獲取到 obj 這個對象的監(jiān)視器鎖的線程才能進入臨界區(qū)。

因此,只要是一個對象,包括字符串實例,理論上都可以被用作加鎖對象。

3、加鎖字符串——看似可行,實則隱患巨大

來看一個例子:

public class StringLockExample {
    public void doSomething(String lock) {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " 獲得了鎖:" + lock);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignored) {}
        }
    }
}

啟動多個線程調(diào)用:

StringLockExample example = new StringLockExample();

Runnable task1 = () -> example.doSomething("LOCK");
Runnable task2 = () -> example.doSomething("LOCK");

new Thread(task1).start();
new Thread(task2).start();

結(jié)果是,兩個線程會串行執(zhí)行,因為加的是同一個字符串 "LOCK" 的鎖。

但問題來了:

字符串是不可變對象,且 JVM 對字符串常量具有“字符串池”優(yōu)化機制(String Interning)!

也就是說:

String a = "LOCK";
String b = "LOCK";
System.out.println(a == b); // true

兩個字符串變量實際上引用的是同一個對象。

因此,在你以為傳進來的是不同的字符串時,可能實際上加的是同一把鎖,或者反過來——你以為加的是同一把鎖,其實不是!

4、字符串加鎖的兩個典型陷阱

4.1 鎖粒度無法控制

如果你的鎖是這樣定義的:

synchronized ("user_" + userId)

你以為這是“每個用戶一個鎖”,但實際上由于字符串拼接會創(chuàng)建新對象,每次拼接都是一個新對象,鎖根本不會生效。

除非你手動 .intern() :

synchronized (("user_" + userId).intern())

這又引入了新的問題:intern 的對象存儲在字符串常量池中,頻繁使用可能會增加內(nèi)存壓力,甚至引發(fā)性能問題。

4.2 外部可控鎖對象

如果你用外部傳入的字符串作為鎖對象,那你根本無法控制到底加的是什么鎖。惡意或不規(guī)范調(diào)用者可能傳入一個常量字符串、空字符串、甚至 null,導(dǎo)致同步行為混亂或拋出異常。

5、安全的替代方案

? 使用自定義鎖對象

最推薦的方式是自己定義一套鎖策略,例如使用 ConcurrentHashMap 管理鎖對象:

private final ConcurrentHashMap<String, Object> lockMap = new ConcurrentHashMap<>();

public void doSomething(String key) {
    Object lock = lockMap.computeIfAbsent(key, k -> new Object());

    synchronized (lock) {
        // 臨界區(qū)
    }
}

這種方式可以保證每個業(yè)務(wù) key 對應(yīng)一個明確的鎖對象,而且不會誤用常量字符串,鎖粒度清晰可控。

6、使用 Google Guava 的 Interner 實現(xiàn)更安全的字符串鎖

Interner 是 Google Guava 提供的一個實用工具類,用于實現(xiàn)“字符串實例的唯一化”。它的作用類似于 String.intern(),但更靈活、可控,不依賴字符串常量池,避免了 JVM 層級的內(nèi)存污染和性能隱患。

引入依賴:

<!-- Maven -->
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>32.1.1-jre</version>
</dependency>

使用示例:

import com.google.common.collect.Interner;
import com.google.common.collect.Interners;

public class GuavaInternerLock {
    private static final Interner<String> interner = Interners.newWeakInterner();

    public void doWork(String key) {
        String internedKey = interner.intern(key);
        synchronized (internedKey) {
            // 同樣 key 的線程會同步執(zhí)行
            System.out.println("Processing key: " + key);
        }
    }
}

Guava Interner 的優(yōu)勢

  • 不污染 JVM 的字符串常量池(不像 String.intern())。
  • 可以選擇 Weak 或 Strong 引用,避免內(nèi)存泄漏。
  • 適合在緩存、去重、分布式任務(wù)分片等場景中鎖定“邏輯鍵”。

7、總結(jié)

并發(fā)編程中,鎖不是萬能的,濫用鎖更是災(zāi)難。本文完整地分析了:

  • synchronized 是否能加鎖字符串(可以,但不推薦);
  • 字符串常量池帶來的鎖隱患;
  • 如何使用 Object、ConcurrentHashMap 構(gòu)建安全鎖;
  • 如何用 Guava 的 Interner 提供高效、可控的鎖機制;
  • 方法參數(shù)中加鎖字符串的風險及解決方案。

寫高質(zhì)量的并發(fā)代碼,關(guān)鍵是理解鎖的語義、作用域和生命周期。希望這篇文章能幫你在并發(fā)之路上走得更穩(wěn)更遠。

到此這篇關(guān)于JAVA中Synchronized能否加鎖字符串的文章就介紹到這了,更多相關(guān)JAVA Synchronized加鎖字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA防止重復(fù)提交Web表單的方法

    JAVA防止重復(fù)提交Web表單的方法

    這篇文章主要介紹了JAVA防止重復(fù)提交Web表單的方法,涉及Java針對表單的相關(guān)處理技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • java 生成有序賬號的實現(xiàn)方法

    java 生成有序賬號的實現(xiàn)方法

    下面小編就為大家?guī)硪黄猨ava 生成有序賬號的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • Java線程生命周期圖文詳細講解

    Java線程生命周期圖文詳細講解

    在java中,任何對象都要有生命周期,線程也不例外,它也有自己的生命周期。線程的整個生命周期可以分為5個階段,分別是新建狀態(tài)、就緒狀態(tài)、運行狀態(tài)、阻塞狀態(tài)和死亡狀態(tài)
    2023-01-01
  • java 實現(xiàn)MD5加密算法的簡單實例

    java 實現(xiàn)MD5加密算法的簡單實例

    這篇文章主要介紹了java 實現(xiàn)MD5加密算法的簡單實例的相關(guān)資料,這里提供實例幫助大家應(yīng)用這樣的加密算法,需要的朋友可以參考下
    2017-09-09
  • Spring?Boot項目中遇到`if-else`語句七種具體使用方法解析

    Spring?Boot項目中遇到`if-else`語句七種具體使用方法解析

    當在Spring?Boot項目中遇到大量if-else語句時,優(yōu)化這些代碼變得尤為重要,因為它們不僅增加了維護難度,還可能影響應(yīng)用程序的可讀性和性能,以下是七種具體的方法,用于在Spring?Boot項目中優(yōu)化和重構(gòu)if-else語句,感興趣的朋友一起看看吧
    2024-07-07
  • 探索Java中的equals()和hashCode()方法_動力節(jié)點Java學(xué)院整理

    探索Java中的equals()和hashCode()方法_動力節(jié)點Java學(xué)院整理

    這篇文章主要介紹了探索Java中的equals()和hashCode()方法的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 利用Spring Social輕松搞定微信授權(quán)登錄的方法示例

    利用Spring Social輕松搞定微信授權(quán)登錄的方法示例

    這篇文章主要介紹了利用Spring Social輕松搞定微信授權(quán)登錄的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • springboot應(yīng)用中使用過濾器的過程詳解

    springboot應(yīng)用中使用過濾器的過程詳解

    過濾器通常用于實現(xiàn)跨切面的功能,例如身份驗證、日志記錄、請求和響應(yīng)的修改、性能監(jiān)控等,這篇文章主要介紹了springboot應(yīng)用中使用過濾器,需要的朋友可以參考下
    2023-06-06
  • java實現(xiàn)Excel高性能異步導(dǎo)出的完整方案詳解

    java實現(xiàn)Excel高性能異步導(dǎo)出的完整方案詳解

    在大型電商系統(tǒng)中,數(shù)據(jù)導(dǎo)出是一個高頻且重要的功能需求,本文將設(shè)計實現(xiàn)一套完整的Excel異步導(dǎo)出機制,通過注解驅(qū)動、任務(wù)隊列、定時調(diào)度、消息通知等技術(shù)手段,完美解決了大數(shù)據(jù)量導(dǎo)出的技術(shù)難題,成為項目的重要技術(shù)亮點
    2025-10-10
  • Java中的Spring.factories文件詳解

    Java中的Spring.factories文件詳解

    文章主要介紹了在SpringBoot項目中如何使用spring.factories文件來注冊項目依賴包中的bean,包括SpringFactories的實現(xiàn)原理、SpringBoot中的SPI機制、SpringFactories在SpringBoot中的應(yīng)用、Beans的配置等內(nèi)容,從而實現(xiàn)解耦的擴展機制,感興趣的朋友一起看看吧
    2026-03-03

最新評論

汽车| 康乐县| 雅江县| 沙雅县| 利辛县| 仙游县| 林口县| 隆林| 大石桥市| 舟山市| 图片| 千阳县| 苍梧县| 湘潭市| 阿拉善左旗| 托里县| 涪陵区| 安吉县| 平陆县| 甘孜县| 延庆县| 博罗县| 前郭尔| 扎囊县| 黑水县| 镇赉县| 深圳市| 芒康县| 德化县| 桂林市| 徐州市| 广东省| 广汉市| 虎林市| 新泰市| 高雄市| 兴宁市| 新丰县| 隆回县| 商城县| 新化县|