欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的線程安全問題詳細解析

 更新時間:2023年11月17日 10:16:58   作者:牧碼ya  
這篇文章主要介紹了Java中的線程安全問題詳細解析,線程安全是如果有多個線程在同時運行,而這些線程可能會同時運行這段代碼,程序每次運行結(jié)果和單線程運行的結(jié)果是一樣的,而且其他的變量的值也和預期的是一樣的,此時我們就稱之為是線程安全的,需要的朋友可以參考下

線程安全

線程安全:如果有多個線程在同時運行,而這些線程可能會同時運行這段代碼。程序每次運行結(jié)果和單線程運行的結(jié)果是一樣的,而且其他的變量的值也和預期的是一樣的,此時我們就稱之為是線程安全的。

我們通過一個案例,演示線程的安全問題:

電影院賣票,使用了A、B、C三個窗口進行賣票,電影票總數(shù)為100張

采用線程對象來模擬賣票窗口A、B、C;使用Runnable接口的子類來模擬買的電影票

模擬電影票:

public class Ticket implements Runnable{
    // 在成員位置 定義票的總數(shù)100
    int ticket = 100;

    @Override
    public void run() {
        // 模擬買票窗口
        // 買票窗口永遠開啟
        while (true){
            // 判斷是否還有票可以賣
            if(ticket > 0){
                // 使用sleep增加“程序的時間”--每張票賣50ms
                try {
                    Thread.sleep(50);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 獲得線程名稱 即買票窗口名稱
                String name = Thread.currentThread().getName();
                System.out.println(name + "賣掉第" + ticket-- + "票");
            }
        }
    }
}

模擬買票:

/**
 * 模擬買票操作
 *    假設一場電影有100張票
 *    三個窗口同時買票
 *
 *    窗口  線程對象
 *    買票  線程任務 實現(xiàn)runnable接口
 */
public class Demo {
    public static void main(String[] args) {
        // 創(chuàng)建買票任務對象
        Ticket ticket = new Ticket();

        // 創(chuàng)建三個窗口
        Thread t1 = new Thread(ticket, "窗口A");
        Thread t2 = new Thread(ticket, "窗口B");
        Thread t3 = new Thread(ticket, "窗口C");

        // 開啟線程
        t1.start();
        t2.start();
        t3.start();
    }
}

運行結(jié)果:

窗口A賣掉第100張票
窗口C賣掉第98張票
窗口B賣掉第99張票
窗口A賣掉第97張票
窗口B賣掉第95張票
窗口C賣掉第96張票
窗口C賣掉第94張票 ⇐
窗口B賣掉第94張票 ⇐
窗口A賣掉第94張票 ⇐
...
窗口C賣掉第1張票
窗口A賣掉第0張票
窗口B賣掉第-1張票 ⇐

發(fā)現(xiàn)程序出現(xiàn)了兩個問題:

1. 相同的票數(shù)被賣了多次,如第94張被三個窗口都賣了

2. 賣出了不存在的票,如窗口B賣掉了第-1張票

此時,幾個窗口(線程)票數(shù)不同步了,這種問題稱為線程不安全。

線程安全問題都是有全局變量即靜態(tài)變量引起的。若每個線程中對全局變量、靜態(tài)變量只有讀操作,而無寫操作。一般來說,這個全局變量是線程安全的;若有多個線程同時執(zhí)行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全

線程同步

當我們使用多個線程訪問同一資源的時候,且多個線程中對資源有些的操作,就容易出現(xiàn)線程安全問題

要解決上述多想成并發(fā)訪問一個資源的安全性問題:也就是解決重復賣同一張票和賣不存在的票問題,Java中提供了同步機制(synchronized)來解決

根據(jù)案例簡述:

窗口A線程進入操作(買票)的時候,窗口B和窗口C線程只能在外等著,窗口A操作結(jié)束,窗口A、窗口B和窗口C(CPU分配內(nèi)存是隨機的,所以還有可能是窗口A進入)才有機會進入代碼去執(zhí)行。

也就是說,在某個線程修改共享資源的時候,其他線程不能修改該資源,等待修改完畢同步之后,才能去搶奪CPU資源,完成對應的操作,保證了數(shù)據(jù)的同步性,解決了線程不安全的現(xiàn)象。

為了保證每個線程都能正常執(zhí)行原子操作,Java引入了線程同步機制。

有三種方式完成同步操作:

1. 同步代碼塊

2. 同步方法

3. 鎖機制

同步代碼塊

同步代碼塊:synchronized 關鍵字可以用于方法中的某個區(qū)塊中,表示只對這個區(qū)塊的資源實行互斥訪問。

格式:

synchronized(同步鎖){
    // 需要同步的操作的代碼
}

同步鎖:

對象的同步鎖只是一個概念,可以想象為在對象上標記了一個鎖。

1. 鎖對象可以是任意類型

2. 多個線程對象要使用同一把鎖

注意:在任何時候,最多允許一個線程擁有同步鎖,誰拿到就進入代碼塊,其他的線程只能在外等著

使用同步代碼塊解決賣票問題:

/**
 * synchronized(鎖對象){
 *
 * }
 * 1. 鎖對象可以是任意類型
 * 2. 互斥線程需要使用同一把鎖
 */
public class Ticket implements Runnable{
    // 在成員位置 定義票的總數(shù)100
    int ticket = 100;

    Object obj = new Object();

    @Override
    public void run() {
        // 模擬買票窗口
        // 買票窗口永遠開啟
        while (true){
            // 同步鎖
            synchronized (obj){
                // 判斷是否還有票可以賣
                if(ticket > 0){
                    // 使用sleep增加“程序的時間”--每張票賣50ms
                    try {
                        Thread.sleep(50);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // 獲得線程名稱 即買票窗口名稱
                    String name = Thread.currentThread().getName();
                    System.out.println(name + "賣掉第" + ticket-- + "票");
                }
            }

        }
    }
}

執(zhí)行結(jié)果:

窗口A賣掉第100票
窗口C賣掉第99票
窗口B賣掉第98票
窗口B賣掉第97票
...
窗口C賣掉第4票
窗口A賣掉第3票
窗口A賣掉第2票
窗口A賣掉第1票

此時,每張票都只會被賣掉一次,不會存在賣掉不存在的電影票的問題。

當使用了同步代碼塊后,上述的線程的安全問題即可解決

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

相關文章

  • 深入理解Java中的EnumMap和EnumSet

    深入理解Java中的EnumMap和EnumSet

    這篇文章主要介紹了深入理解Java中的EnumMap和EnumSet,一般來說我們會選擇使用HashMap來存儲key-value格式的數(shù)據(jù),考慮這樣的特殊情況,一個HashMap的key都來自于一個Enum類,這樣的情況則可以考慮使用本文要講的EnumMap,需要的朋友可以參考下
    2023-11-11
  • Mybatis之RowBounds分頁原理詳解

    Mybatis之RowBounds分頁原理詳解

    這篇文章主要介紹了Mybatis之RowBounds分頁原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • java生成圖片驗證碼返回base64圖片信息方式

    java生成圖片驗證碼返回base64圖片信息方式

    這篇文章主要介紹了java生成圖片驗證碼返回base64圖片信息方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 基于spring三方包類注入容器的四種方式小結(jié)

    基于spring三方包類注入容器的四種方式小結(jié)

    這篇文章主要介紹了基于spring三方包類注入容器的四種方式小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java實現(xiàn)爬蟲給App提供數(shù)據(jù)(Jsoup 網(wǎng)絡爬蟲)

    Java實現(xiàn)爬蟲給App提供數(shù)據(jù)(Jsoup 網(wǎng)絡爬蟲)

    這篇文章主要介紹了Java實現(xiàn)爬蟲給App提供數(shù)據(jù),即Jsoup 網(wǎng)絡爬蟲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-01-01
  • springboot實現(xiàn)配置兩個parent的方法

    springboot實現(xiàn)配置兩個parent的方法

    這篇文章主要介紹了springboot實現(xiàn)配置兩個parent的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java?Stream?API詳解與使用示例詳解

    Java?Stream?API詳解與使用示例詳解

    Java?Stream?API?是一個功能強大的工具,適用于處理集合和數(shù)據(jù)流,本文全面介紹了?Java?Stream?API?的概念、功能以及如何在?Java?中有效地使用它進行集合和數(shù)據(jù)流的處理,感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • Spring Boot thymeleaf模板引擎的使用詳解

    Spring Boot thymeleaf模板引擎的使用詳解

    這篇文章主要介紹了Spring Boot thymeleaf模板引擎的使用詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Java中的字符串常量池詳細介紹

    Java中的字符串常量池詳細介紹

    這篇文章主要介紹了Java中的字符串常量池詳細介紹,JVM為了減少字符串對象的重復創(chuàng)建,其維護了一個特殊的內(nèi)存,這段內(nèi)存被成為字符串常量池或者字符串字面量池,需要的朋友可以參考下
    2015-01-01
  • java 中 poi解析Excel文件版本問題解決辦法

    java 中 poi解析Excel文件版本問題解決辦法

    這篇文章主要介紹了java 中 poi解析Excel文件版本問題解決辦法的相關資料,需要的朋友可以參考下
    2017-08-08

最新評論