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

解決Java中線程安全問題

 更新時間:2026年01月12日 08:50:58   作者:我會替風去  
線程安全問題源于多個線程并發(fā)訪問共享可變資源,破壞了原子性、可見性或有序性,解決方法包括避免共享可變資源、使用同步/加鎖機制以及volatile關鍵字,本文給大家介紹解決Java中線程安全問題,感興趣的朋友跟隨小編一起看看吧

線程安全問題的核心原因

  • 線程安全問題本質是多個線程并發(fā)訪問共享且可變的資源時,操作的原子性、可見性或有序性被破壞,導致程序執(zhí)行結果不符合預期。
  • 根本原因:共享可變資源
  • 共享資源:多個線程都能訪問到的資源(如成員變量、靜態(tài)變量、共享內存區(qū)域);
  • 可變資源:資源的狀態(tài)(值)可以被修改(如int計數(shù)器、HashMap的元素);
  • 經(jīng)典的i++ 操作。它在底層分為“讀取-修改-寫入”三個步驟。如果兩個線程同時讀取 i=1,各自加1后寫回,結果是2而不是3。
  • 直接原因:三大特性被破壞
  • Java內存模型(JMM)定義的多線程并發(fā)三大核心特性,任何一個被破壞都會引發(fā)線程安全問題:
    • 原子性:一個操作(如count++)包含“讀 - 改 - 寫”三步,非原子操作會被多線程交錯執(zhí)行;
    • 可見性:線程修改共享變量后,不會立即同步到主內存,其他線程讀取的仍是舊值;
    • 有序性:JVM的指令重排序優(yōu)化,會導致多線程下執(zhí)行順序混亂(如未加volatile的雙重檢查鎖單例)。

線程安全問題的解決方案

  • 核心思路:要么避免共享可變資源(從根源消除問題),要么控制并發(fā)訪問規(guī)則(保證三大特性)。

方案1:避免共享可變資源(優(yōu)先推薦)

  • 棧封閉(局部變量):局部變量存儲在線程私有棧中,每個線程有獨立副本,天然線程安全。
public class StackClosedDemo {
    // 每個線程調用該方法時,都會創(chuàng)建獨立的count副本
    public void calculate() {
        int count = 0;
        count++; // 無線程安全問題
        System.out.println(Thread.currentThread().getName() + ": " + count);
    }
    public static void main(String[] args) {
        StackClosedDemo demo = new StackClosedDemo();
        // 10個線程各自操作自己的局部變量
        for (int i = 0; i < 10; i++) {
            new Thread(demo::calculate, "Thread-" + i).start();
        }
    }
}
  • 不可變對象:對象創(chuàng)建后狀態(tài)不可修改(如String、Integer),即使共享也無法修改值。
// 自定義不可變類(final類+final成員變量+無setter)
public final class ImmutableUser {
    private final String name;
    private final int age;
    public ImmutableUser(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 僅提供getter,無setter
    public String getName() { return name; }
    public int getAge() { return age; }
}
  • ThreadLocal(線程本地存儲):為每個線程提供獨立的變量副本,線程操作自身副本,互不干擾。
public class ThreadLocalDemo {
    // 每個線程有獨立的Integer副本,初始值為0
    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
    public void increment() {
        threadLocal.set(threadLocal.get() + 1);
        System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
    }
    public static void main(String[] args) {
        ThreadLocalDemo demo = new ThreadLocalDemo();
        // 3個線程各自操作自己的副本
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                for (int j = 0; j < 2; j++) {
                    demo.increment();
                }
            }, "Thread-" + i).start();
        }
    }
}
// 輸出(順序可能不同):
// Thread-0: 1、Thread-0: 2
// Thread-1: 1、Thread-1: 2
// Thread-2: 1、Thread-2: 2

方案2:同步/加鎖(控制并發(fā)訪問)

互斥同步(阻塞同步):這是最常見的方案,通過加鎖來保證同一時刻只有一個線程操作資源。

  • synchronized 關鍵字:Java 原生支持,使用簡單。可修飾方法或代碼塊。屬于不可中斷的鎖。
public class SynchronizedDemo {
    private int count = 0;
    // 同步實例方法,鎖是this對象
    public synchronized void increment() {
        count++;
    }
    public static void main(String[] args) throws InterruptedException {
        SynchronizedDemo demo = new SynchronizedDemo();
        // 1000個線程執(zhí)行increment
        for (int i = 0; i < 1000; i++) {
            new Thread(demo::increment).start();
        }
        Thread.sleep(1000);
        System.out.println("最終count:" + demo.count); // 輸出1000
    }
}

ReentrantLock(顯式鎖):比synchronized靈活(可中斷、可超時、公平鎖),需手動釋放鎖(必須在finally中)。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
    private int count = 0;
    private Lock lock = new ReentrantLock(); // 默認非公平鎖
    public void increment() {
        lock.lock(); // 加鎖
        try {
            count++;
        } finally {
            lock.unlock(); // 釋放鎖,避免死鎖
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo demo = new ReentrantLockDemo();
        for (int i = 0; i < 1000; i++) {
            new Thread(demo::increment).start();
        }
        Thread.sleep(1000);
        System.out.println("最終count:" + demo.count); // 輸出1000
    }
}

方案3:volatile關鍵字(保證可見性/有序性)

  • 保證可見性:強制失效工作內存,直接讀寫主內存。
  • 保證有序性:禁止指令重排序。
  • 注意:它不保證原子性(不能解決i++問題)。
public class VolatileDemo {
    private volatile boolean stop = false; // 保證可見性和有序性
    public void runThread() {
        new Thread(() -> {
            int i = 0;
            while (!stop) { // 能立即感知stop的修改
                i++;
            }
            System.out.println("線程停止,i=" + i);
        }).start();
    }
    public static void main(String[] args) throws InterruptedException {
        VolatileDemo demo = new VolatileDemo();
        demo.runThread();
        Thread.sleep(3000);
        demo.stop = true; // 修改后,線程立即停止
    }
}

到此這篇關于Java中線程安全問題的原因和解決方案的文章就介紹到這了,更多相關java線程安全內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現(xiàn)基本排序算法的示例代碼

    Java實現(xiàn)基本排序算法的示例代碼

    排序就是將一串記錄按照其中某個或某些關鍵字的大小,遞增或遞減的排列起來的操作。本文將用Java實現(xiàn)一些基本的排序算法,感興趣的可以了解一下
    2022-07-07
  • SpringBoot ResponseBody返回值處理的實現(xiàn)

    SpringBoot ResponseBody返回值處理的實現(xiàn)

    這篇文章主要介紹了SpringBoot ResponseBody返回值處理的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • 使用SpringBoot+AOP實現(xiàn)可插拔式日志的示例代碼

    使用SpringBoot+AOP實現(xiàn)可插拔式日志的示例代碼

    這篇文章主要介紹了使用SpringBoot+AOP實現(xiàn)可插拔式日志的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • SpringBoot 動態(tài)配置郵箱發(fā)件人過程解析

    SpringBoot 動態(tài)配置郵箱發(fā)件人過程解析

    這篇文章主要介紹了SpringBoot 動態(tài)配置郵箱發(fā)件人過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • Java最簡單的DES加密算法實現(xiàn)案例

    Java最簡單的DES加密算法實現(xiàn)案例

    下面小編就為大家?guī)硪黄狫ava最簡單的DES加密算法實現(xiàn)案例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Springboot集成Ehcache3實現(xiàn)本地緩存的配置方法

    Springboot集成Ehcache3實現(xiàn)本地緩存的配置方法

    EhCache是一個純Java的進程內緩存框架,是 Hibernate 中默認的 CacheProvider,同Redis一樣,EhCache 不是純內存緩存,它支持基于內存和磁盤的二級緩存,本文介紹Springboot集成Ehcache3實現(xiàn)本地緩存的配置方法,感興趣的朋友一起看看吧
    2024-04-04
  • java代碼實現(xiàn)雙向鏈表

    java代碼實現(xiàn)雙向鏈表

    這篇文章主要為大家詳細介紹了java代碼實現(xiàn)雙向鏈表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Java 如何從spring容器中獲取注入的bean對象

    Java 如何從spring容器中獲取注入的bean對象

    這篇文章主要介紹了Java 如何從spring容器中獲取注入的bean對象,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-11-11
  • Java數(shù)據(jù)結構之順序表詳解

    Java數(shù)據(jù)結構之順序表詳解

    這篇文章主要介紹了Java數(shù)據(jù)結構之順序表詳解,線性表在邏輯上是線性結構,也就說是連續(xù)的一條直線。但是在物理結構上并不一定是連續(xù)的,線性表在物理上存儲時,通常以數(shù)組和鏈式結構的形式存儲,需要的朋友可以參考下
    2023-07-07
  • 深入解析Java的設計模式編程中的模板方法模式

    深入解析Java的設計模式編程中的模板方法模式

    這篇文章主要介紹了深入解析Java的設計模式編程中的模板方法模式, 模版方法模式由一個抽象類和一個(或一組)實現(xiàn)類通過繼承結構組成,需要的朋友可以參考下
    2016-02-02

最新評論

赤壁市| 库尔勒市| 泸州市| 集安市| 临清市| 集贤县| 玉门市| 玉溪市| 图木舒克市| 南川市| 双桥区| 平江县| 武威市| 黑山县| 民县| 城口县| 夏河县| 四子王旗| 广丰县| 措勤县| 华宁县| 清苑县| 怀仁县| 太仓市| 云霄县| 盐池县| 广东省| 保山市| 井冈山市| 洪湖市| 五台县| 剑河县| 肃南| 江口县| 罗山县| 天峨县| 农安县| 淮阳县| 邹平县| 东光县| 武威市|