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

Java線程安全問題的解決方案

 更新時間:2022年05月10日 10:14:33   作者:??Java中文社群????  
這篇文章主要介紹了Java線程安全問題的解決方案,文章關(guān)于安全的問題的解決方案本文主要分享了三種方法,使用線程安全類,比如?AtomicInteger,使用線程本地變量?ThreadLocal,加鎖排隊執(zhí)行,三種方法的使用場景及區(qū)別需要的小伙伴可以參考一下

前言:

線程安全是指某個方法或某段代碼,在多線程中能夠正確的執(zhí)行,不會出現(xiàn)數(shù)據(jù)不一致或數(shù)據(jù)污染的情況,我們把這樣的程序稱之為線程安全的,反之則為非線程安全的。在 Java 中,

解決線程安全問題有以下 3 種手段:

  • 使用線程安全類,比如 AtomicInteger。
  • 加鎖排隊執(zhí)行
    • 使用 synchronized 加鎖。
    • 使用 ReentrantLock 加鎖。
  • 使用線程本地變量 ThreadLocal。

接下來我們逐個來看它們的實現(xiàn)。

線程安全問題演示

我們創(chuàng)建一個變量 number 等于 0,之后創(chuàng)建線程 1,執(zhí)行 100 萬次 ++ 操作,同時再創(chuàng)建線程 2 執(zhí)行 100 萬次 -- 操作,等線程 1 和線程 2 都執(zhí)行完之后,打印 number 變量的值,如果打印的結(jié)果為 0,則說明是線程安全的,否則則為非線程安全的,

示例代碼如下:

public class ThreadSafeTest {
    // 全局變量
    private static int number = 0;
    // 循環(huán)次數(shù)(100W)
    private static final int COUNT = 1_000_000;

    public static void main(String[] args) throws InterruptedException {
        // 線程1:執(zhí)行 100W 次 ++ 操作
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                number++;
            }
        });
        t1.start();

        // 線程2:執(zhí)行 100W 次 -- 操作
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                number--;
            }
        });
        t2.start();

        // 等待線程 1 和線程 2,執(zhí)行完,打印 number 最終的結(jié)果
        t1.join();
        t2.join();
        System.out.println("number 最終結(jié)果:" + number);
    }
}

以上程序的執(zhí)行結(jié)果如下圖所示: 

 從上述執(zhí)行結(jié)果可以看出,number 變量最終的結(jié)果并不是 0,和預(yù)期的正確結(jié)果不相符,這就是多線程中的線程安全問題。

解決線程安全問題

1.原子類AtomicInteger

AtomicInteger 是線程安全的類,使用它可以將 ++ 操作和 -- 操作,變成一個原子性操作,這樣就能解決非線程安全的問題了,

如下代碼所示:

import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerExample {
    // 創(chuàng)建 AtomicInteger
    private static AtomicInteger number = new AtomicInteger(0);
    // 循環(huán)次數(shù)
    private static final int COUNT = 1_000_000;

    public static void main(String[] args) throws InterruptedException {
        // 線程1:執(zhí)行 100W 次 ++ 操作
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                // ++ 操作
                number.incrementAndGet();
            }
        });
        t1.start();

        // 線程2:執(zhí)行 100W 次 -- 操作
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                // -- 操作
                number.decrementAndGet();
            }
        });
        t2.start();

        // 等待線程 1 和線程 2,執(zhí)行完,打印 number 最終的結(jié)果
        t1.join();
        t2.join();
        System.out.println("最終結(jié)果:" + number.get());
    }
}

以上程序的執(zhí)行結(jié)果如下圖所示: 

2.加鎖排隊執(zhí)行

Java 中有兩種鎖:synchronized 同步鎖和 ReentrantLock 可重入鎖。

2.1 同步鎖synchronized

synchronized 是 JVM 層面實現(xiàn)的自動加鎖和自動釋放鎖的同步鎖,它的實現(xiàn)代碼如下:

public class SynchronizedExample {
    // 全局變量
    private static int number = 0;
    // 循環(huán)次數(shù)(100W)
    private static final int COUNT = 1_000_000;

    public static void main(String[] args) throws InterruptedException {
        // 線程1:執(zhí)行 100W 次 ++ 操作
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                // 加鎖排隊執(zhí)行
                synchronized (SynchronizedExample.class) {
                    number++;
                }
            }
        });
        t1.start();

        // 線程2:執(zhí)行 100W 次 -- 操作
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                // 加鎖排隊執(zhí)行
                synchronized (SynchronizedExample.class) {
                    number--;
                }
            }
        });
        t2.start();

        // 等待線程 1 和線程 2,執(zhí)行完,打印 number 最終的結(jié)果
        t1.join();
        t2.join();
        System.out.println("number 最終結(jié)果:" + number);
    }
}

以上程序的執(zhí)行結(jié)果如下圖所示: 

2.2 可重入鎖ReentrantLock

ReentrantLock 可重入鎖需要程序員自己加鎖和釋放鎖,它的實現(xiàn)代碼如下:

import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用 ReentrantLock 解決非線程安全問題
 */
public class ReentrantLockExample {
    // 全局變量
    private static int number = 0;
    // 循環(huán)次數(shù)(100W)
    private static final int COUNT = 1_000_000;
    // 創(chuàng)建 ReentrantLock
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        // 線程1:執(zhí)行 100W 次 ++ 操作
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                lock.lock();    // 手動加鎖
                number++;       // ++ 操作
                lock.unlock();  // 手動釋放鎖
            }
        });
        t1.start();

        // 線程2:執(zhí)行 100W 次 -- 操作
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                lock.lock();    // 手動加鎖
                number--;       // -- 操作
                lock.unlock();  // 手動釋放鎖
            }
        });
        t2.start();

        // 等待線程 1 和線程 2,執(zhí)行完,打印 number 最終的結(jié)果
        t1.join();
        t2.join();
        System.out.println("number 最終結(jié)果:" + number);
    }
}

以上程序的執(zhí)行結(jié)果如下圖所示: 

3.線程本地變量ThreadLocal

使用 ThreadLocal 線程本地變量也可以解決線程安全問題,它是給每個線程獨自創(chuàng)建了一份屬于自己的私有變量,不同的線程操作的是不同的變量,所以也不會存在非線程安全的問題,它的實現(xiàn)代碼如下:

public class ThreadSafeExample {
    // 創(chuàng)建 ThreadLocal(設(shè)置每個線程中的初始值為 0)
    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
    // 全局變量
    private static int number = 0;
    // 循環(huán)次數(shù)(100W)
    private static final int COUNT = 1_000_000;

    public static void main(String[] args) throws InterruptedException {
        // 線程1:執(zhí)行 100W 次 ++ 操作
        Thread t1 = new Thread(() -> {
            try {
                for (int i = 0; i < COUNT; i++) {
                    // ++ 操作
                    threadLocal.set(threadLocal.get() + 1);
                }
                // 將 ThreadLocal 中的值進行累加
                number += threadLocal.get();
            } finally {
                threadLocal.remove(); // 清除資源,防止內(nèi)存溢出
            }
        });
        t1.start();

        // 線程2:執(zhí)行 100W 次 -- 操作
        Thread t2 = new Thread(() -> {
            try {
                for (int i = 0; i < COUNT; i++) {
                    // -- 操作
                    threadLocal.set(threadLocal.get() - 1);
                }
                // 將 ThreadLocal 中的值進行累加
                number += threadLocal.get();
            } finally {
                threadLocal.remove(); // 清除資源,防止內(nèi)存溢出
            }
        });
        t2.start();

        // 等待線程 1 和線程 2,執(zhí)行完,打印 number 最終的結(jié)果
        t1.join();
        t2.join();
        System.out.println("最終結(jié)果:" + number);
    }
}

以上程序的執(zhí)行結(jié)果如下圖所示: 

總結(jié)

在 Java 中,解決線程安全問題的手段有 3 種:1.使用線程安全的類,如 AtomicInteger 類;2.使用鎖 synchronized 或 ReentrantLock 加鎖排隊執(zhí)行;3.使用線程本地變量 ThreadLocal 來處理。

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

相關(guān)文章

  • java isPalindrome方法在密碼驗證中的應(yīng)用

    java isPalindrome方法在密碼驗證中的應(yīng)用

    這篇文章主要為大家介紹了java isPalindrome方法在密碼驗證中的簡單應(yīng)用技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Java線程中的Timer和TimerTask原理詳解

    Java線程中的Timer和TimerTask原理詳解

    這篇文章主要介紹了Java線程中的Timer和TimerTask原理詳解,Timer和TimerTask成對出現(xiàn),Timer是定時器,TimerTask是定時任務(wù),換句話說,定時任務(wù)TimerTask是給定時器Timer執(zhí)行的具體任務(wù),需要的朋友可以參考下
    2023-10-10
  • Spring Security自定義失敗處理器問題

    Spring Security自定義失敗處理器問題

    這篇文章主要介紹了Spring Security自定義失敗處理器問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • java 繼承訪問成員變量代碼實例

    java 繼承訪問成員變量代碼實例

    這篇文章主要介紹了java 繼承訪問成員變量代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • 在IDEA中配置Maven鏡像的最新方法

    在IDEA中配置Maven鏡像的最新方法

    這篇文章主要給大家介紹了關(guān)于在IDEA中配置Maven鏡像的最新方法,Maven是一個流行的Java項目構(gòu)建工具,它依賴于互聯(lián)網(wǎng)上的Mave中央倉庫來下載和管理項目依賴庫,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2023-11-11
  • Java之Spring AOP 實現(xiàn)用戶權(quán)限驗證

    Java之Spring AOP 實現(xiàn)用戶權(quán)限驗證

    本篇文章主要介紹了Java之Spring AOP 實現(xiàn)用戶權(quán)限驗證,用戶登錄、權(quán)限管理這些是必不可少的業(yè)務(wù)邏輯,具有一定的參考價值,有興趣的可以了解一下。
    2017-02-02
  • java實現(xiàn)馬踏棋盤的完整版

    java實現(xiàn)馬踏棋盤的完整版

    這篇文章主要為大家詳細介紹了java實現(xiàn)馬踏棋盤的完整版,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Spring導(dǎo)入properties配置文件代碼示例

    Spring導(dǎo)入properties配置文件代碼示例

    這篇文章主要介紹了Spring導(dǎo)入properties配置文件代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • 模擬Mybatis的實現(xiàn)方法

    模擬Mybatis的實現(xiàn)方法

    本文通過實例代碼給大家分享了模擬Mybatis的實現(xiàn)方法,需要的朋友參考下吧
    2017-09-09
  • Java下載https文件并上傳阿里云oss服務(wù)器

    Java下載https文件并上傳阿里云oss服務(wù)器

    這篇文章主要介紹了Java下載https文件并上傳到阿里云oss服務(wù)器,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01

最新評論

诸暨市| 白城市| 伽师县| 克拉玛依市| 嘉祥县| 乌恰县| 富川| 依兰县| 利川市| 开江县| 汽车| 溧阳市| 启东市| 青铜峡市| 大姚县| 上虞市| 定日县| 延安市| 稻城县| 清新县| 江源县| 百色市| 蚌埠市| 东宁县| 四川省| 东至县| 红河县| 醴陵市| 山丹县| 洞口县| 焦作市| 武川县| 延川县| 朔州市| 白山市| 台北县| 宝鸡市| 水富县| 太保市| 安西县| 拉孜县|