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

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

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

前言:

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

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

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

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

線程安全問題演示

我們創(chuàng)建一個(gè)變量 number 等于 0,之后創(chuàng)建線程 1,執(zhí)行 100 萬次 ++ 操作,同時(shí)再創(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 是線程安全的類,使用它可以將 ++ 操作和 -- 操作,變成一個(gè)原子性操作,這樣就能解決非線程安全的問題了,

如下代碼所示:

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.加鎖排隊(duì)執(zhí)行

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

2.1 同步鎖synchronized

synchronized 是 JVM 層面實(shí)現(xiàn)的自動(dòng)加鎖和自動(dòng)釋放鎖的同步鎖,它的實(shí)現(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++) {
                // 加鎖排隊(duì)執(zhí)行
                synchronized (SynchronizedExample.class) {
                    number++;
                }
            }
        });
        t1.start();

        // 線程2:執(zhí)行 100W 次 -- 操作
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                // 加鎖排隊(duì)執(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 可重入鎖需要程序員自己加鎖和釋放鎖,它的實(shí)現(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();    // 手動(dòng)加鎖
                number++;       // ++ 操作
                lock.unlock();  // 手動(dòng)釋放鎖
            }
        });
        t1.start();

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

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

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

3.線程本地變量ThreadLocal

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

public class ThreadSafeExample {
    // 創(chuàng)建 ThreadLocal(設(shè)置每個(gè)線程中的初始值為 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 中的值進(jìn)行累加
                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 中的值進(jìn)行累加
                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 加鎖排隊(duì)執(zhí)行;3.使用線程本地變量 ThreadLocal 來處理。

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

相關(guān)文章

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

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

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

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

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

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

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

    java 繼承訪問成員變量代碼實(shí)例

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評(píng)論

安陆市| 华阴市| 分宜县| 同德县| 孝感市| 舞阳县| 鹰潭市| 江源县| 鄂温| 历史| 五指山市| 中超| 福海县| 日照市| 大洼县| 拉孜县| 启东市| 合水县| 宾阳县| 华池县| 大安市| 南丰县| 特克斯县| 朝阳市| 化州市| 霍山县| 个旧市| 凉城县| 阜新市| 乐平市| 江津市| 西华县| 沂南县| 青州市| 淳安县| 黑龙江省| 北碚区| 新龙县| 德江县| 长葛市| 宿州市|