沧州空调移机:Java并发编程实战 01并发编程的Bug源头

admin 5个月前 (04-15) 科技 37 0

〖摘要〗

编写准确[的“并发”程序对【我来说】是一件极其难题“的事”情,<由于知识不足>,「只知道」synchronized“这个修饰符举行同步”。
「本文<为>学习」“极客时间”:Java“并”发编程实战 01(的《总结》),《『文章』取图也》是来自于该『文章』

“并发”Bug【源头】

<在>计算机系统(‘中’),『程序的执行速』率<为>:CPU > <内存> > I/O“装备” ,《<为>了平》衡这三者的速率 差<异>[,〖计算机系统机构〗、「「操」作系统」、《编译程序都举行了优》化:

1.CPU(增加了缓存), 以平衡[和<内存>的速率 差<异>[
2.「「操」作系统」增加了历程、{“「<线程>」”},〖已分时复用〗CPU, 以平衡[ CPU {与} I/O “装备”的速率 差<异>[
3.(编译程)序优化 指[令执行〖顺序〗,【使】得缓存能够加倍合理「的行使」。

(然则这)三者导致的<<“【《问题》】”>><为>:((可见性))、【「原子性」】、(有序性)

【源头】之一:CPU缓存导致的((可见性))<<“【《问题》】”>>

一个{“「<线程>」”}对共享变量的【修改】,另外一个{“「<线程>」”}能够立刻「看(<到>)」,那么就称<为>((可见性))。
『现在多核』CPU《时代(‘中’)》,『每颗』CPU〖都有自己的〗缓存,CPU〖之间并不会〗共享缓存;

《如》{“「<线程>」”}A从<内存>读取变量V(<到>)CPU-1,“「操」作”完成{<(<「后」>)>}保存在CPU-1「缓存(‘中’)」,还未写(<到>)<内存>(‘中’)。
此时{“「<线程>」”}B从<内存>读取变量V(<到>)CPU-2(‘中’),“而”CPU-1「缓存(‘中’)」的变量V对{“「<线程>」”}B〖是《不能见》〗的
当{“「<线程>」”}A【把更新{<(<「后」>)>}的变量】V写(<到>)<内存>(‘中’)时,{“「<线程>」”}B才可以从<内存>(‘中’)读取(<到>)『最新变量』V(的值)

上述历程就是{“「<线程>」”}A【修改】变量V{<(<「后」>)>},对{“「<线程>」”}B《不能见》,那么就称<为>((可见性))<<“【《问题》】”>>。

【源头】之二:{“「<线程>」”}切{换}带来的【「原子性」】<<“【《问题》】”>>

现代的「「操」作系统」都是基于{“「<线程>」”}来调剂的,现在提(<到>)的“{义务切{换}}”(都是)指“{“「<线程>」”}切{换}”
Java“并发”程序都是基于多{“「<线程>」”}的,自然也会涉及(<到>){义务切{换}},在高级语言(‘中’),【一《条》语句可】能就需要多《条》CPU『 指[令完成』,<例《如》在代码> count += 1 (‘中’),至少需要三《条》CPU 指[令。

指[令1:〖把〗变量 count 从<内存>加载(<到>)CPU的寄存器(‘中’)
指[令2:在寄存器(‘中’)〖把〗变量 count + 1
指[令3:〖把〗变量 count 写入(<到>)<内存>(‘缓存机制’导致可能写入 的是[CPU缓存“而”不是<内存>)

「「操」作系统」做{义务切{换}},可以发生在任何一《条》CPU 指[令『执行完』,以是并不是高级语言(‘中’)的一《条》语句, 不要被[ count += 1 {这个「操」作蒙蔽了双眼}。<假设>count = 0,{“「<线程>」”}A『执行完』 指[令1 {<(<「后」>)>} ,做{义务切{换}}(<到>){“「<线程>」”}B【执行了】 指[令1、 指[令2、 指[令3{<(<「后」>)>},再做{义务切{换}}回{“「<线程>」”}A。我们会发现虽然两个{“「<线程>」”}都【执行了】 count += 1 「操」作。{然则获得的效果并不是}2,“而”是1。

「若是」 count += 1 『是一』个不能分割的整体,{“「<线程>」”}的切{换}可以发生在 count += 1 之前或之{<(<「后」>)>},然则不会发生在(‘中’)心,‘就像个原子’一样。我们把一个或者多个「操」(作在) CPU 执行的历程(‘中’)不被(‘中’)止的特征称<为>【「原子性」】

【源头】之三:编译优化带来的(有序性)<<“【《问题》】”>>

(有序性)指 的是[程序根据代码的先{<(<「后」>)>}〖顺序〗执行。编译器<为>了优化性能,可能会改变程序(‘中’)的语句执行先{<(<「后」>)>}〖顺序〗。《如》:a = 1; b = 2;,<编译器可能会优化成>:b = 2; a = 1。在这个例子(‘中’),『编译器优化了程序的执』行先{<(<「后」>)>}〖顺序〗,「并不影」响效果。然则有时刻优化{<(<「后」>)>}会导致意想不(<到>)的Bug。
“在单例模式的”双重检查建立单例「「工具」」(‘中’)。《如》下代码:

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

<<“【《问题》】”>>出现在了new Singletion()“这行代码”,我们以<为>的执行〖顺序〗应{该是这样的}:

指[令1:分配一块<内存>M
指[令2:在<内存>M(‘中’)实例化Singleton「「工具」」
指[令3:instance变量指向<内存>地址M

然则现实优化{<(<「后」>)>}的执行(「路」径确实这样的):

指[令1:分配一块<内存>M
指[令2:instance变量指向<内存>地址M
指[令3:在<内存>M(‘中’)实例化Singleton「「工具」」

这样的话看出来什么<<“【《问题》】”>>了吗?当{“「<线程>」”}A『执行完』了 指[令2{<(<「后」>)>},切{换}(<到>)了{“「<线程>」”}B,
{“「<线程>」”}B判断(<到>) if (instance != null)。“直接返回”instance,〖然〗则此时的instance(照样)没有被实例化的啊!{以}是这时刻我们使用instance可能就会触发空指针<异>『常了』。《如》图:

《总结》

在写“并发”程序的时刻,需要时刻注重((可见性))、【「原子性」】、(有序性)的<<“【《问题》】”>>。在深刻理解这三个<<“【《问题》】”>>{<(<「后」>)>},写起“并发”程序也会少一《点》Bug(啦)~。<记住了下>面这段话:CPU缓存会带来((可见性))<<“【《问题》】”>>、{“「<线程>」”}切{换}带来的【「原子性」】<<“【《问题》】”>>、编译优化带来的(有序性)<<“【《问题》】”>>。

参考『文章』:“极客时间”:Java“并”发编程实战 01 | ((可见性))、【「原子性」】和(有序性)<<“【《问题》】”>>:“并发”编程Bug的【源头】

《小》我私家博客网址: https://colablog.cn/

「若是」我的『文章』辅助(<到>)您,《可以关注我的微信民众》<号>,第一时间分享『文章』给您
沧州空调移机:Java并发编程实战 01并发编程的Bug源头 第1张

,

Sunbet

《菲律宾长滩岛》旅游攻略 最专业权[威的媒体人搜集<社会>热《点》资讯,【推】送内容精准可靠,(针对用户个性化需)求,整合各界热《点》专题,《以》新媒体传播的方式挖〖掘最〗新最热门资讯,<为>您提供您感兴趣的新闻{与}生活内容, (涵盖了时政)、「财」经、<社会>、《教育》、{情感等全方位多角度}的《新闻报》道分析,{同时开拓您}的眼界和思「路」, 让您足不出户就能[一揽《天下》。

欧博开户声明:该文看法仅代表作者自己,与本平台无关。转载请注明:沧州空调移机:Java并发编程实战 01并发编程的Bug源头

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:444
  • 页面总数:0
  • 分类总数:8
  • 标签总数:980
  • 评论总数:105
  • 浏览总数:2752