自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

事與愿違:可變類出現(xiàn)了線程安全問(wèn)題

開(kāi)發(fā) 前端
理解可變類引發(fā)線程安全問(wèn)題的原因,重點(diǎn)理解什么是可變類,以及可變類在多線程環(huán)境下存在的問(wèn)題,能夠結(jié)合自身實(shí)際項(xiàng)目思考哪些場(chǎng)景下可變類會(huì)引發(fā)線程安全問(wèn)題,并能夠思考問(wèn)題背后的解決方案。

大家好,我是冰河~~

“確實(shí)在公司跟著老大能學(xué)到很多知識(shí)啊,之前確實(shí)也不怎么了解線程安全問(wèn)題和一些解決方案,現(xiàn)在了解了,也終于基于不可變類實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的功能,明天找老大幫我看看“,小菜心里想著,臉上露出了滿意的微笑。

一、情景再現(xiàn)

上回說(shuō)到:小菜在自己實(shí)現(xiàn)分配的統(tǒng)計(jì)商品詳情接口調(diào)用次數(shù)的功能時(shí),沒(méi)注意線程安全問(wèn)題,導(dǎo)致統(tǒng)計(jì)出來(lái)的結(jié)果數(shù)據(jù)與實(shí)際結(jié)果偏差較大,通過(guò)老王的耐心講解,知道了背后產(chǎn)生問(wèn)題的根本原因,也學(xué)到了幾種并發(fā)問(wèn)題的解決方案。

下班后,小菜自己嘗試基于不可變類實(shí)現(xiàn)一個(gè)簡(jiǎn)單的功能,但是。。。

二、事與愿違

第二天,小菜早早來(lái)到公司,昨天自己想基于不可變類實(shí)現(xiàn)一個(gè)簡(jiǎn)單的功能,經(jīng)過(guò)自己不懈的努力,終于“完成”了自己想象的功能,心里也是比較高興的。就等著老王來(lái)公司后,給老王看看自己實(shí)現(xiàn)的功能。

正想著,小菜聽(tīng)到了老王說(shuō)話的聲音,原來(lái)是老王跟幾個(gè)同事一起到公司了??粗贤踝叩搅俗约旱墓の簧希〔四弥约旱碾娔X來(lái)到老王身邊說(shuō):”老大,我昨天學(xué)了不少并發(fā)問(wèn)題的解決方案,對(duì)不可變類這種方式很感興趣,回去后自己基于這種方式實(shí)現(xiàn)了一個(gè)小功能,你幫我看看實(shí)現(xiàn)的對(duì)嗎?“。

老王聽(tīng)后說(shuō):“我看看,你給我簡(jiǎn)單說(shuō)下實(shí)現(xiàn)的功能是啥?”。

“咱們乘坐高鐵,在進(jìn)站時(shí)不是都要通過(guò)身份證檢票嗎,我就想通過(guò)不可變類模擬實(shí)現(xiàn)一個(gè)檢票的功能,這個(gè)檢票功能支持并發(fā)訪問(wèn),也就是同時(shí)支持多個(gè)人拿著身份證通過(guò)檢票。

在實(shí)現(xiàn)上,我想的比較簡(jiǎn)單,就是通過(guò)一個(gè)名字和身份證編號(hào)來(lái)定義一個(gè)不可變類,表示一個(gè)用戶,由這個(gè)不可變類支持線程安全。再由一個(gè)Map來(lái)存儲(chǔ)這些用戶的信息,當(dāng)用戶通過(guò)檢票時(shí),更新下用戶的信息,最終打印出來(lái)。整個(gè)過(guò)程基于不可變類實(shí)現(xiàn)線程安全”。

“我還畫了一張圖”,說(shuō)著小菜從電腦里打開(kāi)了自己畫的場(chǎng)景需求圖,如圖4-1所示。

圖片

老王聽(tīng)了后說(shuō):“嗯,我大概明白你的需求了,我看看代碼實(shí)現(xiàn)”。

于是小菜便把電腦給了老王,要不說(shuō)老王是大牛呢?老王只是用他那凌厲的眼掃了一眼,便說(shuō)道:“這代碼有問(wèn)題”。

“啊”,小菜當(dāng)時(shí)就有點(diǎn)懵,“這,我覺(jué)得沒(méi)問(wèn)題呀”。。。

三、分析代碼

“那我們就結(jié)合代碼來(lái)分析下原因吧”,老王說(shuō)著,便讓小菜看代碼?!笆紫仁沁@個(gè)User用戶類”。

User類的源碼詳見(jiàn):concurrent-design-patterns-immutable工程下的io.binghe.concurrent.design.demo.wrong.User。

public class User {

    private String name;
    private Long idCard;

    public void set(String name, Long idCard){
        this.name = name;
        this.idCard = idCard;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", idCard=" + idCard +
                '}';
    }
}

“這個(gè)User類就是有問(wèn)題的,你知道什么是不可變類嗎?”,老王問(wèn)小菜。

小菜說(shuō):“知道,就是一個(gè)類一經(jīng)創(chuàng)建,就不會(huì)發(fā)生變化的類,就叫做不可變類”。

“對(duì),概念記得倒是挺清楚的,但是這個(gè)User類不是一個(gè)不可變類呀,我們根據(jù)不可變類的定義分析下這個(gè)User類為什么不是一個(gè)不可變類”,老王巴拉巴拉的說(shuō)了起來(lái)??傮w上,老王針對(duì)User類為什么不是不可變類,總結(jié)了如下幾點(diǎn):

  • 用戶類沒(méi)有被final修飾,可以有其他類繼承User類,一旦有子類繼承,就可能改變User類的狀態(tài)。
  • User類里的成員變量沒(méi)有被final修飾,可能會(huì)發(fā)生變化。
  • User類中提供了修改成員變量的方法。成員變量可能發(fā)生變化。
  • User類的set()方法也不是原子的,存在線程安全問(wèn)題,多個(gè)線程同時(shí)訪問(wèn)可能會(huì)存在并發(fā)問(wèn)題。

“明白了嗎?”,老王問(wèn)小菜。

“明白了”,小菜回答道,“其實(shí)我總覺(jué)得哪里有點(diǎn)怪,就是說(shuō)不上來(lái),我以為我寫的是對(duì)的”,小菜不好意思的笑了笑。

“那我們?cè)賮?lái)看看你寫的這個(gè)TicketCheck類”,老王繼續(xù)說(shuō)道,說(shuō)著打開(kāi)了小菜寫的TicketCheck類的代碼片段。

TicketCheck類的源碼詳見(jiàn):concurrent-design-patterns-immutable工程下的io.binghe.concurrent.design.demo.wrong.TicketCheck。

public class TicketCheck {

    private Map<String, User> userMap = new ConcurrentHashMap<>();

    public void updateUser(String userKey, String userName, Long idCard){
        User user = userMap.get(userKey);
        user.set(userName, idCard);
        System.out.println(Thread.currentThread().getName() + "--當(dāng)前檢票的用戶是:" + user.toString());
        userMap.put(userKey, user);
    }

    public User getUser(String userKey){
        return userMap.get(userKey);
    }
}

“這個(gè)類也相對(duì)比較簡(jiǎn)單”,老王繼續(xù)說(shuō)道:“但是這類會(huì)改變User對(duì)象內(nèi)部的狀態(tài),User類本身就不是一個(gè)不可變類,加上TicketCheck類也確實(shí)通過(guò)用戶類的set()方法改變了用戶類的狀態(tài),如果多個(gè)線程訪問(wèn)了同一個(gè)userKey中的User對(duì)象,就可能會(huì)存在線程安全問(wèn)題,所以整體不能基于不可變類保證線程安全”。

此時(shí)的小菜有點(diǎn)一臉懵逼,眉頭擰成了一個(gè)麻花。

老王看了一眼小菜,說(shuō)到:“剛才我說(shuō)的聽(tīng)明白了嗎?”。

“有點(diǎn)聽(tīng)不明白了”,我寫的TicketCheck類,其實(shí)并不是要修改User類,而是為User類設(shè)置userName和idCard屬性,實(shí)際并不會(huì)修改User類的信息,只是記錄檢票的用戶,并且打印用戶的信息,不太明白為啥不能基于不可變類保證線程安全“。

“這樣吧,我給你畫張圖分析一下”,老王說(shuō)道。

于是,老王打開(kāi)了電腦的畫圖工具。。。

四、畫圖分析

要不說(shuō)老王這人就是牛,對(duì)其他同事也特別好呢,不一會(huì),就畫出了一張分析圖,如圖4-2所示。

圖片

“我們就基于你寫的User類進(jìn)行講解,看這張圖”,老王繼續(xù)說(shuō)到,“假設(shè)現(xiàn)在user對(duì)象的name為張三,idCard為1001,線程1獲取到用戶信息時(shí),此時(shí)的name為張三,idCard為1001,線程1調(diào)用user對(duì)象的set()方法來(lái)修改用戶的信息。我們來(lái)看user的set()方法”,老王又打開(kāi)了User類的代碼,重點(diǎn)讓小菜看set()方法的代碼。

public void set(String name, Long idCard){
    this.name = name;
    this.idCard = idCard;
}

“在set()方法中,會(huì)分別修改user的name字段和idCard的值,這個(gè)過(guò)程并不是原子操作,線程1在執(zhí)行set()方法時(shí),在更新完name字段的值時(shí),如果此時(shí)恰好發(fā)生了線程切換,線程2獲取用戶信息時(shí),獲取到的用戶的name字段為張三,idCard字段為1001。這時(shí),線程2獲取到的數(shù)據(jù)是錯(cuò)亂的,線程2獲取到的用戶name字段為李四,idCard卻是張三的身份證編號(hào),用戶數(shù)據(jù)發(fā)生了錯(cuò)亂的現(xiàn)象,出現(xiàn)了線程安全問(wèn)題”。

“這么說(shuō)能聽(tīng)明白嗎?”,老王又問(wèn)小菜。

“嗯,這次明白了”,小菜回復(fù)到。

“那我們繼續(xù)講講怎么寫不可變類的代碼吧”,老王接著說(shuō)。

“好的”。

正當(dāng)老王準(zhǔn)備講如何寫不可變類的代碼時(shí),此時(shí)聽(tīng)到一個(gè)熟悉的聲音,“王工,有個(gè)新的需求要和技術(shù)這邊一起討論下可行性,你參與一下呀?”,老王抬頭一看,原來(lái)是產(chǎn)品經(jīng)理,邊說(shuō)邊往這邊走,于是回了句:“好的”。

老王轉(zhuǎn)過(guò)有來(lái)對(duì)小菜說(shuō):“那我們今天就到這兒,你先結(jié)合今天分析的內(nèi)容,思考下怎么寫不可變的類,有時(shí)間咱們?cè)俳又?,我去開(kāi)會(huì)”。(老王真特么是個(gè)大好人)。

“好的”,小菜接著說(shuō)。

于是,老王拿著電腦跟產(chǎn)品經(jīng)理去開(kāi)會(huì)了,小菜回到了自己的工位,開(kāi)始了一天的工作。。。

五、本章總結(jié)

本章,以場(chǎng)景故事的形式描述了不可變類存在的線程安全問(wèn)題,以及對(duì)不可變類存在的線程安全問(wèn)題進(jìn)行了分析。

責(zé)任編輯:姜華 來(lái)源: 冰河技術(shù)
相關(guān)推薦

2023-09-26 21:59:48

安全REST軟件架構(gòu)

2020-06-14 08:55:24

網(wǎng)絡(luò)安全信息泄露網(wǎng)絡(luò)釣魚

2012-02-21 14:14:47

Java

2024-09-17 17:50:28

線程線程安全代碼

2022-04-11 10:56:43

線程安全

2011-03-29 10:41:51

Java線程安全

2016-11-23 15:48:05

iOS APPCache

2021-03-23 18:32:46

JavaScript編程開(kāi)發(fā)

2021-07-26 06:57:59

Synchronize線程安全

2019-04-04 11:55:59

2012-11-20 10:47:16

2022-12-30 21:26:56

2009-05-30 09:36:18

2022-04-06 07:50:28

線程安全代碼

2011-03-21 10:23:06

2013-04-02 11:07:16

2009-11-03 13:46:56

Oracle密碼

2013-09-05 09:42:06

2011-11-17 10:34:14

內(nèi)網(wǎng)安全

2012-12-11 11:28:20

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)