成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我們一起聊聊從操作系統(tǒng)層面理解多線程沖突

開發(fā) 前端
同一進(jìn)程內(nèi)的線程是共享同一內(nèi)存空間的,所以在多個(gè)線程的進(jìn)程里,線程是可以同時(shí)操作這個(gè)進(jìn)程空間的數(shù)據(jù)的,線程之間可以共享進(jìn)程的資源:比如代碼段、堆空間、數(shù)據(jù)段、打開的文件等資源,但每個(gè)線程也有自己獨(dú)立的棧空間。

前言

今天來從操作系統(tǒng)層面理解一下多線程沖突的問題,話不多說,開始~~

什么是多線程的沖突

同一進(jìn)程內(nèi)的線程是共享同一內(nèi)存空間的,所以在多個(gè)線程的進(jìn)程里,線程是可以同時(shí)操作這個(gè)進(jìn)程空間的數(shù)據(jù)的,線程之間可以共享進(jìn)程的資源:比如代碼段、堆空間、數(shù)據(jù)段、打開的文件等資源,但每個(gè)線程也有自己獨(dú)立的棧空間。如果多個(gè)線程如果競(jìng)爭(zhēng)共享資源,如果不采取有效的措施,則會(huì)造成共享數(shù)據(jù)的混亂。

舉個(gè)小栗子:一個(gè)房子里(代表一個(gè)進(jìn)程),只有一個(gè)廁所(代表共享資源)。屋子里面有兩個(gè)人A和B(代表兩個(gè)線程),共用這個(gè)廁所。一天A去上廁所了,不過廁所門的鎖壞了,就沒法鎖門。這是B也想去上廁所,直接就開門進(jìn)去了,然后發(fā)現(xiàn)A在里面。

上面這個(gè)故事說明,對(duì)于共享資源,如果沒有上鎖,在多線程的環(huán)境里,那么就可能會(huì)發(fā)生翻車現(xiàn)場(chǎng)。

競(jìng)爭(zhēng)與協(xié)作

做個(gè)小實(shí)驗(yàn),創(chuàng)建五個(gè)線程,它們分別對(duì)共享變量 i 自增 1 執(zhí)行 1000 次

package com.atguigu.juc.atomics;

public class Station{


    int i = 0;

    public void add() {
        for(int m = 0; m < 1000; m++){
            try {
                //使用sleep()模擬業(yè)務(wù)時(shí)間,如果不加,大概率不會(huì)出現(xiàn)并發(fā)問題
                Thread.sleep(1);
                i += 1;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        //實(shí)例化站臺(tái)對(duì)象,并為每一個(gè)站臺(tái)取名字
        Station station = new Station();
        new Thread(station::add,"線程1").start();
        new Thread(station::add,"線程2").start();
        new Thread(station::add,"線程3").start();
        new Thread(station::add,"線程4").start();
        new Thread(station::add,"線程5").start();
        Thread.sleep(20000);
        // 讓每一個(gè)站臺(tái)對(duì)象各自開始工作
        System.out.println(station.i);
        Thread.sleep(5000);
        System.out.println(station.i);
    }
}

運(yùn)行了幾次發(fā)現(xiàn),每次運(yùn)行得到不同的結(jié)果。在計(jì)算機(jī)里是不能容忍的,雖然是小概率出現(xiàn)的錯(cuò)誤,但是小概率事件它一定是會(huì)發(fā)生的。

為什么會(huì)出現(xiàn)這樣的問題呢?

為了理解為什么會(huì)發(fā)生這種情況,我們必須了解編譯器為更新計(jì)數(shù)器 i 變量生成的代碼序列,也就是要了解匯編指令的執(zhí)行順序。

在這個(gè)例子中,我們只是想給 i 加上數(shù)字 1,那么它對(duì)應(yīng)的匯編指令執(zhí)行過程是這樣的:

可以發(fā)現(xiàn),只是單純給 i 加上數(shù)字 1,在 CPU 運(yùn)行的時(shí)候,實(shí)際上要執(zhí)行 3 條指令。

設(shè)想我們的線程 1 進(jìn)入這個(gè)代碼區(qū)域,它將 i 的值(假設(shè)此時(shí)是 50 )從內(nèi)存加載到它的寄存器中,然后它向寄存器加 1,此時(shí)在寄存器中的 i 值是 51。

現(xiàn)在,一件不幸的事情發(fā)生了:當(dāng)前線程被掛起了,線程 2 被調(diào)度運(yùn)行,并進(jìn)入同一段代碼。它也執(zhí)行了第一條指令,從內(nèi)存獲取 i 值并將其放入到寄存器中,此時(shí)內(nèi)存中 i 的值仍為 50,因此線程 2 寄存器中的 i 值也是 50。假設(shè)線程 2 執(zhí)行接下來的兩條指令,將寄存器中的 i 值 + 1,然后將寄存器中的 i 值保存到內(nèi)存中,于是此時(shí)全局變量 i 值是 51。

最后,又發(fā)生一次上下文切換,線程 1 恢復(fù)執(zhí)行。還記得它已經(jīng)執(zhí)行了兩條匯編指令,現(xiàn)在準(zhǔn)備執(zhí)行最后一條指令。回憶一下, 線程 1 寄存器中的 i 值是51,因此,執(zhí)行最后一條指令后,將值保存到內(nèi)存,全局變量 i 的值再次被設(shè)置為 51。

簡(jiǎn)單來說,增加 i (值為 50 )的代碼被運(yùn)行兩次,按理來說,最后的 i 值應(yīng)該是 52,但是由于不可控的調(diào)度,導(dǎo)致最后 i 值卻是 51。

針對(duì)上面線程 1 和線程 2 的執(zhí)行過程,我畫了一張流程圖,會(huì)更明確一些:

互斥的概念

上面展示的情況稱為競(jìng)爭(zhēng)條件(race condition),當(dāng)多線程相互競(jìng)爭(zhēng)操作共享變量時(shí),由于運(yùn)氣不好,即在執(zhí)行過程中發(fā)生了上下文切換,我們得到了錯(cuò)誤的結(jié)果,事實(shí)上,每次運(yùn)行都可能得到不同的結(jié)果,因此輸出的結(jié)果存在不確定性(indeterminate)。

由于多線程執(zhí)行操作共享變量的這段代碼可能會(huì)導(dǎo)致競(jìng)爭(zhēng)狀態(tài),因此我們將此段代碼稱為臨界區(qū)(critical section),它是訪問共享資源的代碼片段,一定不能給多線程同時(shí)執(zhí)行。

我們希望這段代碼是互斥(mutualexclusion)的,也就說保證一個(gè)線程在臨界區(qū)執(zhí)行時(shí),其他線程應(yīng)該被阻止進(jìn)入臨界區(qū),說白了,就是這段代碼執(zhí)行過程中,最多只能出現(xiàn)一個(gè)線程。

另外,說一下互斥也并不是只針對(duì)多線程。在多進(jìn)程競(jìng)爭(zhēng)共享資源的時(shí)候,也同樣是可以使用互斥的方式來避免資源競(jìng)爭(zhēng)造成的資源混亂。

同步的概念

所謂同步,就是并發(fā)進(jìn)程/線程在一些關(guān)鍵點(diǎn)上可能需要互相等待與互通消息,這種相互制約的等待與互通信息稱為進(jìn)程/線程同步。

上面那個(gè)栗子:一A去上廁所了,發(fā)現(xiàn)廁所門的鎖壞了,告訴B一聲。這是B想去上廁所的話,就會(huì)先問一下A是不是還在里面,然后再開門進(jìn)去了。這也是互通消息的方式,如果鎖沒有壞,A直接把門鎖上,這就是相互等待的方式。

怎么解決多線程沖突?

為了實(shí)現(xiàn)進(jìn)程/線程間正確的協(xié)作,操作系統(tǒng)必須提供實(shí)現(xiàn)進(jìn)程協(xié)作的措施和方法,主要的方法有兩種:

  • 鎖:加鎖、解鎖操作;
  • 信號(hào)量:P、V 操作;

這兩個(gè)都可以方便地實(shí)現(xiàn)進(jìn)程/線程互斥,而信號(hào)量比鎖的功能更強(qiáng)一些,它還可以方便地實(shí)現(xiàn)進(jìn)程/線程同步。

使用加鎖操作和解鎖操作可以解決并發(fā)線程/進(jìn)程的互斥問題。

任何想進(jìn)入臨界區(qū)的線程,必須先執(zhí)行加鎖操作。若加鎖操作順利通過,則線程可進(jìn)入臨界區(qū);在完成對(duì)臨界資源的訪問后再執(zhí)行解鎖操作,以釋放該臨界資源。

信號(hào)量

信號(hào)量是操作系統(tǒng)提供的一種協(xié)調(diào)共享資源訪問的方法。通常信號(hào)量表示資源的數(shù)量,對(duì)應(yīng)的變量是一個(gè)整型(sem)變量。

另外,還有兩個(gè)原子操作的系統(tǒng)調(diào)用函數(shù)來控制信號(hào)量的,分別是:

  • P 操作:將 sem 減 1,相減后,如果 sem < 0,則進(jìn)程/線程進(jìn)入阻塞等待,否則繼續(xù),表明 P 操作可能會(huì)阻塞;
  • V 操作:將 sem 加 1,相加后,如果 sem <= 0,喚醒一個(gè)等待中的進(jìn)程/線程,表明 V 操作不會(huì)阻塞;

舉個(gè)類比,2 個(gè)資源的信號(hào)量,相當(dāng)于 2 條火車軌道,PV 操作如下圖過程:


責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2022-09-22 08:06:29

計(jì)算機(jī)平板微信

2023-06-09 08:06:14

操作系統(tǒng)調(diào)度器LLM

2024-02-28 08:41:51

Maven沖突版本

2024-06-04 07:52:04

2023-07-11 08:34:25

參數(shù)流程類型

2023-08-02 08:35:54

文件操作數(shù)據(jù)源

2021-12-10 07:45:48

字節(jié)音頻視頻

2012-02-22 10:48:23

操作系統(tǒng)

2025-02-28 08:46:24

框架微服務(wù)架構(gòu)

2024-12-10 00:00:25

2023-10-31 09:04:21

CPU調(diào)度Java

2024-02-20 21:34:16

循環(huán)GolangGo

2021-08-27 07:06:10

IOJava抽象

2023-08-10 08:28:46

網(wǎng)絡(luò)編程通信

2023-08-04 08:20:56

DockerfileDocker工具

2023-06-30 08:18:51

敏捷開發(fā)模式

2022-05-24 08:21:16

數(shù)據(jù)安全API

2023-09-10 21:42:31

2021-10-26 09:55:52

CAP理論分布式

2012-06-06 10:38:32

Windows操作系統(tǒng)
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 成人在线视频免费观看 | 中文字幕av在线播放 | 91精品国产91久久久久久 | 四虎最新视频 | av永久| a国产视频| 在线欧美亚洲 | 中文字幕在线免费视频 | 999www视频免费观看 | 香蕉视频久久久 | 午夜精品福利视频 | 中文亚洲视频 | 色吧久久 | 日韩高清在线观看 | 久久久性色精品国产免费观看 | h视频在线观看免费 | 亚洲精品成人在线 | 精品国产欧美一区二区三区成人 | 欧美一级免费 | 免费观看一级特黄欧美大片 | 欧美精品乱码久久久久久按摩 | 羞羞在线观看视频 | 国产高潮好爽受不了了夜色 | 91短视频网址 | 国产成人一区二区 | 羞羞网站在线观看 | 999久久久久久久久6666 | 成人亚洲精品久久久久软件 | 国产成人99久久亚洲综合精品 | 久草在线在线精品观看 | 日韩欧美国产成人一区二区 | 国产精品日韩欧美一区二区三区 | 国产一区二区三区久久久久久久久 | 国产精品区二区三区日本 | 国产成人精品久久二区二区91 | 日韩在线中文字幕 | 欧美在线a | 欧美a区 | 亚洲国产精品一区二区第一页 | 日韩欧美网 | 日韩一区二区三区视频 |