国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)

這篇具有很好參考價(jià)值的文章主要介紹了【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)

??????點(diǎn)進(jìn)來你就是我的人了
博主主頁:??????戳一戳,歡迎大佬指點(diǎn)!

歡迎志同道合的朋友一起加油喔??????【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)


目錄

前言

1. 造成線程不安全的原因有哪些呢?

1.1什么是原子性

1.2什么是內(nèi)存可見性

1.3共享變量可見性實(shí)現(xiàn)的原理

?1.4 什么是指令重排序

2.解決線程安全問題

2.1 引入關(guān)鍵字synchronized解決線程不安全問題

(1)?synchronized的使用方法(鎖)

(2)synchronized的作用

?(3)優(yōu)化后的代碼(加鎖后)

2.2. 關(guān)于鎖/同步監(jiān)視器的總結(jié)(重點(diǎn)掌握):

總結(jié)1:認(rèn)識(shí)同步監(jiān)視器(鎖) ? ----- ?synchronized(同步監(jiān)視器){ }

總結(jié)2:同步代碼塊的執(zhí)行過程(重點(diǎn)理解)

總結(jié)3:多個(gè)代碼塊使用同一個(gè)同步監(jiān)視器(鎖)

2.3. 引入volatile解決線程安全問題

(1)?volatile保證內(nèi)存可見性

(2) volatile禁止指令重排序



前言

? ? ? ??在多線程環(huán)境下如果說代碼運(yùn)行的結(jié)果是符合我們預(yù)期的,即該代碼在單線程中運(yùn)行得到的結(jié)果,那么就說這個(gè)程序是線程安全的,否則就是線程不安全的.下面帶大家仔細(xì)給大家講解一下線程不安全問題!


1. 造成線程不安全的原因有哪些呢?

1)搶占式執(zhí)行,調(diào)度過程隨機(jī)(也是萬惡之源,無法解決)

2)多個(gè)線程同時(shí)修改同一個(gè)變量(可以適當(dāng)調(diào)整代碼結(jié)構(gòu),避免這種情況)

3)針對(duì)變量的操作,不是原子的(加鎖,synchronized)

4)內(nèi)存可見性,一個(gè)線程頻繁讀,一個(gè)線程寫(使用volatile)

5)指令重排序(使用synchronized加鎖或者volatile禁止指令重排序)

1.1什么是原子性

案例引入

我們把一段代碼想象成一個(gè)房間,每個(gè)線程就是要進(jìn)入這個(gè)房間的人。如果沒有任何機(jī)制保證,A進(jìn)入房間之后,還沒有出來;B 是不是也可以進(jìn)入房間,打斷 A 在房間里的隱私。這個(gè)就是不具備原子性的!

那我們應(yīng)該如何解決這個(gè)問題呢?是不是只要給房間加一把鎖,A 進(jìn)去就把門鎖上,其他人是不是就進(jìn)不來了。這樣就保證了這段代碼的原子性了。
有時(shí)也把這個(gè)現(xiàn)象叫做同步互斥,表示操作是互相排斥的。

一條 java 語句不一定是原子的,也不一定只是一條指令(例如++操作,內(nèi)部三條指令構(gòu)成)

原子性是指一個(gè)操作或者多個(gè)操作,要么全部執(zhí)行,并且執(zhí)行的過程不會(huì)被任何因素打斷,要么就都不執(zhí)行。

一組操作(一行或多行代碼)是不可拆分的最小執(zhí)行單位,就表示這組操作是具有原子性

多個(gè)線程多次的并發(fā)并行的對(duì)一個(gè)共享變量操作時(shí),該操作就不具有原子性

在Java中,對(duì)基本數(shù)據(jù)類型的變量的讀取和賦值操作是原子性操作,即這些操作是不可被中斷的,要么執(zhí)行,要么不執(zhí)行。

上面一句話雖然看起來簡單,但是理解起來并不是那么容易??聪旅嬉粋€(gè)例子:

x = 10; 	//語句1
y = x; 		//語句2
x++; 		//語句3
x = x + 1; 	//語句4

注意其實(shí)只有語句1是原子性操作,其他三個(gè)語句都不是原子性操作。

  • 語句1是直接將數(shù)值10賦值給x,也就是說線程執(zhí)行這個(gè)語句的會(huì)直接將數(shù)值10寫入到工作內(nèi)存中。
  • 語句2實(shí)際上包含2個(gè)操作,它先要去讀取x的值,再將x的值寫入工作內(nèi)存,雖然讀取x的值以及將x的值寫入工作內(nèi)存,這2個(gè)操作都是原子性操作,但是合起來就不是原子性操作了。
  • 同樣的,x++和 x = x+1包括3個(gè)操作:讀取x的值,進(jìn)行加1操作,寫入新的值

也就是說,只有簡單的讀取、賦值(而且必須是將數(shù)字賦值給某個(gè)變量,變量之間的相互賦值不是原子操作)才是原子操作。

從上面可以看出,Java內(nèi)存模型只保證了基本讀取和賦值是原子性操作,如果要實(shí)現(xiàn)更大范圍操作的原子性,可以通過synchronized和Lock來實(shí)現(xiàn)。

由于synchronized和Lock能夠保證任一時(shí)刻只有一個(gè)線程執(zhí)行該代碼塊,那么自然就不存在原子性問題了,從而保證了原子性。

1.2什么是內(nèi)存可見性

多個(gè)線程工作的時(shí)候都是在自己的工作內(nèi)存中來執(zhí)行操作的,線程之間是不可見

1. 線程之間的共享變量存在主內(nèi)存(實(shí)際內(nèi)存)
2. 每一個(gè)線程都有自己的工作內(nèi)存(CPU寄存器+緩存)
3. 線程讀取共享變量時(shí),先把變量從主存拷貝到工作內(nèi)存,再從工作內(nèi)存讀取數(shù)據(jù)
4. 線程修改共享變量時(shí),先修改工作內(nèi)存中的變量值,再同步到主內(nèi)存

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)?

注意:

(1)線程對(duì)共享變量的所有操作都必須在自己的工作內(nèi)存中進(jìn)行,不能繞過工作內(nèi)存直接從主內(nèi)存中讀寫變量

(2)不同線程之間無法直接訪問其他線程工作內(nèi)存中的變量,線程之間變量值的傳遞需要通過主內(nèi)存來完成

此時(shí)引入了兩個(gè)問題
????????為啥要整這么多內(nèi)存?
????????為啥要這么麻煩的拷來拷去?
1) 為啥整這么多內(nèi)存?
實(shí)際并沒有這么多 "內(nèi)存". 這只是 Java 規(guī)范中的一個(gè)術(shù)語, 是屬于 "抽象" 的叫法.
所謂的 "主內(nèi)存" 才是真正硬件角度的 "內(nèi)存". 而所謂的 "工作內(nèi)存", 則是指 CPU 的寄存器和高速緩存
2) 為啥要這么麻煩的拷來拷去?
因?yàn)?CPU 訪問自身寄存器的速度以及高速緩存的速度, 遠(yuǎn)遠(yuǎn)超過訪問內(nèi)存的速度(快了 3 - 4 個(gè)數(shù)量級(jí), 也就是幾千倍, 上萬倍).
比如某個(gè)代碼中要連續(xù) 10 次讀取某個(gè)變量的值, 如果 10 次都從內(nèi)存讀, 速度是很慢的. 但是如果只是第一次從內(nèi)存讀, 讀到的結(jié)果緩存到 CPU 的某個(gè)寄存器中, 那么后 9 次讀數(shù)據(jù)就不必直接訪問內(nèi)存了. 效率就大大提高了.
那么接下來問題又來了, 既然訪問寄存器速度這么快, 還要內(nèi)存干啥??
答案就是一個(gè)字: 貴
值的一提的是, 快和慢都是相對(duì)的. CPU 訪問寄存器速度遠(yuǎn)遠(yuǎn)快于內(nèi)存, 但是內(nèi)存的訪問速度又遠(yuǎn)遠(yuǎn)快于硬盤.對(duì)應(yīng)的, CPU 的價(jià)格最貴, 內(nèi)存次之, 硬盤最便宜

1.3共享變量可見性實(shí)現(xiàn)的原理

線程1對(duì)共享變量的修改要想被線程2及時(shí)看到,必須要經(jīng)過如下的2個(gè)步驟

(1)把工作內(nèi)存1中更新過的共享變量刷新到主內(nèi)存中

(2)將主內(nèi)存中最新的共享變量的值更新到工作內(nèi)存2中

變量傳遞順序

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)?

?1.4 什么是指令重排序

JVM翻譯字節(jié)碼指令,CPU執(zhí)行機(jī)器碼指令,都可能發(fā)生重排序來優(yōu)化執(zhí)行效率

比如有這樣三步操作:(1) 去前臺(tái)取U盤 (2) 去教室寫作業(yè) (3) 去前臺(tái)取快遞
JVM會(huì)對(duì)指令優(yōu)化,也就是重排序,新的順序?yàn)?1)(3)(2),這樣就可以少跑一次前臺(tái),以此提高效率,這就叫做指令重排序.

編譯器對(duì)于指令重排序的前提是 "保持邏輯不發(fā)生變化". 這一點(diǎn)在單線程環(huán)境下比較容易判斷, 但
是在多線程環(huán)境下就沒那么容易了, 多線程的代碼執(zhí)行復(fù)雜程度更高, 編譯器很難在編譯階段對(duì)代
碼的執(zhí)行效果進(jìn)行預(yù)測(cè), 因此激進(jìn)的重排序很容易導(dǎo)致優(yōu)化后的邏輯和之前不等價(jià).
重排序是一個(gè)比較復(fù)雜的話題, 涉及到 CPU 以及編譯器的一些底層工作原理, 此處不做過多討論

?

2.解決線程安全問題

引入count++問題

class Counter {
    private int count =0;
    public void add() {
            count++;
    }
    public int getCount() {
        return count;
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter =new Counter();
        Thread t1 =new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        Thread t2 =new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(counter.getCount());
    }
}

運(yùn)行上述代碼我們會(huì)發(fā)現(xiàn)每次都結(jié)果是小于100000的,因?yàn)樯厦鎯蓚€(gè)線程在實(shí)際對(duì)count進(jìn)行++操作的時(shí)候并不滿足原子性,導(dǎo)致最終的結(jié)果一直不是我們想要的,這就是由于不滿足原子性所導(dǎo)致的線程不安全問題!!!

count++操作,本質(zhì)上是有三個(gè)CPU指令構(gòu)成

1.load,把內(nèi)存中的數(shù)據(jù)讀到CPU寄存器中

2.add,就是把寄存器中的值進(jìn)行+1運(yùn)算

3.save,把寄存器中的值寫回到內(nèi)存中

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)

? ?由于CPU的搶占式執(zhí)行,導(dǎo)致兩個(gè)線程同時(shí)進(jìn)行count++操作的時(shí)候,內(nèi)部的三個(gè)CPU指令不能完整一次性執(zhí)行完,例如在第一個(gè)線程在執(zhí)行的時(shí)候先讀取共享變量count的值到自己的寄存器中,還沒來得及修改,第二個(gè)線程獲取到了CPU的執(zhí)行權(quán)開始執(zhí)行,此時(shí)線程2線讀取共享變量到自己的工作內(nèi)存(寄存器中)進(jìn)行修改,最后再同步到主內(nèi)存(就是更新共享變量count的值),當(dāng)線程2執(zhí)行完畢后,線程1再次獲得CPU的執(zhí)行權(quán)繼續(xù)執(zhí)行未完成的操作,將自己寄存器中的count進(jìn)行修改再同步到主內(nèi)存中,此時(shí)由于兩次修改實(shí)際上只修改成功一次,這就是由于原子性引起的線程不安全問題!

2.1 引入關(guān)鍵字synchronized解決線程不安全問題

(1)?synchronized的使用方法(鎖)

修飾方法:修飾普通方法時(shí),關(guān)鍵字在public前后都可,鎖對(duì)象是 this,也就是誰調(diào)用誰上鎖。修飾靜態(tài)方法時(shí),鎖對(duì)象是類對(duì)象。

修飾代碼塊:修飾代碼塊時(shí),顯式(手動(dòng))指定鎖對(duì)象。

對(duì)于構(gòu)造方法來說,如果加鎖,不能直接加在方法上,但是內(nèi)部可以使用代碼塊的方法,來加鎖。

代碼演示

    
    //修飾普通方法
    public synchronized void doSomething(){
        //...
    }

    //修飾代碼塊
    public void doSomething(){
        synchronized (this) {
            //...
        }
    }
    
    //修飾靜態(tài)方法(與下面效果相同都是鎖類對(duì)象)
    public static synchronized void doSomething(){
        //...
    }

    //修飾靜態(tài)方法
    public static void doSomething(){
        synchronized (A.class) {
            //...
        }
    }

(2)synchronized的作用

sychronized是基于對(duì)象頭加鎖的,特別注意:不是對(duì)代碼加鎖,所說的加鎖操作就是給這個(gè)對(duì)象的對(duì)象頭里設(shè)置了一個(gè)標(biāo)志位

一個(gè)對(duì)象在同一時(shí)間只能有一個(gè)線程獲取到該對(duì)象的鎖
sychronized保證了原子性,可見性,有序性(這里的有序不是指指令重排序,而是具有相同鎖的代碼塊按照獲取鎖的順序執(zhí)行)

(2.1) 互斥性

synchronized 會(huì)起到互斥效果, 某個(gè)線程執(zhí)行到某個(gè)對(duì)象的 synchronized 中時(shí), 其他線程如果也執(zhí)行到同一個(gè)對(duì)象 synchronized 就會(huì)阻塞等待

進(jìn)入 synchronized 修飾的代碼塊, 相當(dāng)于 加鎖
退出 synchronized 修飾的代碼塊, 相當(dāng)于 解鎖

下面圖加深理解:

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)

阻塞等待:

針對(duì)每一把鎖, 操作系統(tǒng)內(nèi)部都維護(hù)了一個(gè)等待隊(duì)列. 當(dāng)這個(gè)鎖被某個(gè)線程占有的時(shí)候,其他線程嘗試進(jìn)行加鎖, 就加不上了,就會(huì)阻塞等待, 一直等到之前的線程解鎖之后, 由操作系統(tǒng)喚醒一個(gè)新的線程, 再來獲取到這個(gè)鎖!

(2.2)?刷新主存

synchronized鎖住共享變量時(shí)的工作流程:

??獲得互斥鎖
??從主存拷貝最新的變量到工作內(nèi)存
??對(duì)變量執(zhí)行操作
??將修改后的共享變量的值刷新到主存
??釋放互斥鎖

(2.3)?可重入性

synchronized是可重入鎖
同一個(gè)線程可以多次申請(qǐng)成功一個(gè)對(duì)象鎖

在可重入鎖的內(nèi)部, 包含了 "線程持有者" 和 "計(jì)數(shù)器" 兩個(gè)信息.
如果某個(gè)線程加鎖的時(shí)候, 發(fā)現(xiàn)鎖已經(jīng)被人占用, 但是恰好占用的正是自己, 那么仍然可以繼續(xù)獲取
到鎖, 并讓計(jì)數(shù)器自增.
解鎖的時(shí)候計(jì)數(shù)器遞減為 0 的時(shí)候, 才真正釋放鎖. (才能被別的線程獲取到)

????????可重入鎖的意義就是降低程序員負(fù)擔(dān)(使用成本來提高開發(fā)效率),代價(jià)就是程序的開銷增大(維護(hù)鎖屬于哪個(gè)線程,并且加減計(jì)數(shù),降低了運(yùn)行效率)?

如下圖:

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)

?(3)優(yōu)化后的代碼(加鎖后)

class Counter {
    private int count =0;
    synchronized public void add() {
            count++;
    }
    public int getCount() {
        return count;
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter =new Counter();
        Thread t1 =new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        Thread t2 =new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(counter.getCount());
    }
}

2.2. 關(guān)于鎖/同步監(jiān)視器的總結(jié)(重點(diǎn)掌握):

總結(jié)1:認(rèn)識(shí)同步監(jiān)視器(鎖) ? ----- ?synchronized(同步監(jiān)視器){ }

??必須是引用數(shù)據(jù)類型,不能是基本數(shù)據(jù)類型
??也可以創(chuàng)建一個(gè)專門的同步監(jiān)視器,沒有任何業(yè)務(wù)含義?
??一般使用共享資源做同步監(jiān)視器即可 ??
??在同步代碼塊中不能改變同步監(jiān)視器對(duì)象的引用?

??盡量不要String和包裝類Integer做同步監(jiān)視器?
??建議使用final修飾同步監(jiān)視器

【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)

總結(jié)2:同步代碼塊的執(zhí)行過程(重點(diǎn)理解)

1)第一個(gè)線程來到同步代碼塊,發(fā)現(xiàn)同步監(jiān)視器open狀態(tài),需要close,然后執(zhí)行其中的代碼
2)第一個(gè)線程執(zhí)行過程中,發(fā)生了線程切換(處于阻塞就緒狀態(tài)),第一個(gè)線程失去了cpu但是沒有開鎖(open)
3)第二個(gè)線程獲取了cpu,來到了同步代碼塊,發(fā)現(xiàn)同步監(jiān)視器close狀態(tài),無法執(zhí)行其中的代碼,第二個(gè)線程也進(jìn)入阻塞狀態(tài)
4)第一個(gè)線程再次獲取CPU,接著執(zhí)行后續(xù)的代碼;同步代碼塊執(zhí)行完畢,釋放鎖open
5)第二個(gè)線程也再次獲取cpu,來到了同步代碼塊,發(fā)現(xiàn)同步監(jiān)視器open狀態(tài),拿到鎖并且上鎖,由阻塞狀態(tài)進(jìn)入就緒狀態(tài),再進(jìn)入運(yùn)行狀態(tài),重復(fù)第一個(gè)線程的處理過程(加鎖)
強(qiáng)調(diào):同步代碼塊中能發(fā)生CPU的切換嗎?能?。?! 但是后續(xù)的被執(zhí)行的線程也無法執(zhí)行同步代碼塊(因?yàn)殒i仍舊close)?

總結(jié)3:多個(gè)代碼塊使用同一個(gè)同步監(jiān)視器(鎖)

1)多個(gè)代碼塊使用了同一個(gè)同步監(jiān)視器(鎖),鎖住一個(gè)代碼塊的同時(shí),也鎖住所有使用該鎖的所有代碼塊,其他線程無法訪問其中的任何一個(gè)代碼塊?
2)多個(gè)代碼塊使用了同一個(gè)同步監(jiān)視器(鎖),鎖住一個(gè)代碼塊的同時(shí),也鎖住所有使用該鎖的所有代碼塊, 但是沒有鎖住使用其他同步監(jiān)視器的代碼塊,其他線程有機(jī)會(huì)訪問其他同步監(jiān)視器的代碼塊

2.3. 引入volatile解決線程安全問題

(1)?volatile保證內(nèi)存可見性

引入一個(gè)線程不安全的場(chǎng)景:

當(dāng)一個(gè)線程對(duì)一個(gè)變量進(jìn)行讀取操作,同時(shí)另一個(gè)線程針對(duì)這個(gè)變量進(jìn)行修改,此時(shí)讀到的值不一定是修改后的值,這是編譯器在多線程環(huán)境下優(yōu)化時(shí)產(chǎn)生了誤判,從而引起了bug

代碼演示:

class Sign{
     public boolean flag = false;
}
 
public class ThreadDemo4{
 
 
    public static void main(String[] args) {
        Sign sign = new Sign();
 
        Thread t1 = new Thread(()->{
 
            while(!sign.flag){
 
            }
            System.out.println("執(zhí)行完畢");
        });
        Thread t2 = new Thread(()->{
            sign.flag = true;
        });
        t1.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        t2.start();
 
    }
}

運(yùn)行上述代碼我們會(huì)發(fā)現(xiàn),程序會(huì)一直運(yùn)行,while感知不到flag的變化。原因就是,執(zhí)行到線程2的時(shí)候,while一直循環(huán)跑了好多遍,flag一直是false,所以編譯器對(duì)代碼進(jìn)行優(yōu)化,默認(rèn)為程序不變,不再從內(nèi)存中讀取flag的值,而是讀取寄存器中不變的flag的值,等到線程2執(zhí)行到flag變量后,盡管修改掉了內(nèi)存中flag的值,但是寄存器中的flag依舊為原來的值,所以while一直感知到的flag是沒變的,一直循環(huán)跑。

那么如何解決該問題呢?

用volatile來修飾變量,通過保證內(nèi)存可見性來解決上述問題,每次讀取用volatile修飾的變量的值,都會(huì)從主內(nèi)存中讀取該變量。

通俗地講:volatile變量在每次被線程訪問時(shí),都強(qiáng)迫從主內(nèi)存中重讀該變量的值,而當(dāng)該變量發(fā)生變化時(shí),又會(huì)強(qiáng)迫線程將最新的值刷新到主內(nèi)存。這樣在任何時(shí)刻,不同的線程總能看到該變量的最新值。

那么,線程修改volatile變量的過程:

(1)改變線程工作內(nèi)存中volatile變量副本的值

(2)將改變后的副本的值從工作內(nèi)存刷新到主內(nèi)存

線程讀volatile變量的值的過程:

(1)從主內(nèi)存中讀取volatile變量的最新值到線程的工作內(nèi)存中

(2)從工作內(nèi)存中讀取volatile變量的副本

(2) volatile禁止指令重排序

我們這里拿實(shí)例化一個(gè)對(duì)象舉例

SomeObject s=new SomeObject();? //保證對(duì)象實(shí)例化正確

1.堆里申請(qǐng)內(nèi)存空間,初始化為0x0

2.對(duì)象初始化工作:構(gòu)造代碼塊,屬性的定義時(shí)初始化,構(gòu)造方法(這才算是一個(gè)正確對(duì)象)

3.賦值給s

volatile禁止重排序,只能1->2->3,如果1->3->2在3到2之間有線程(線程調(diào)度隨機(jī))使用對(duì)象,其對(duì)象是錯(cuò)的即出現(xiàn)問題。

能準(zhǔn)確的表明其作用是單列模式:(這個(gè)我們后面會(huì)再講)

單列模式分為餓漢模式(在類加載期間就進(jìn)行對(duì)象實(shí)例化),懶漢模式(第一次用到時(shí)進(jìn)行對(duì)象的實(shí)例化)

其懶漢模式實(shí)現(xiàn)如下:假如多個(gè)線程走先判斷對(duì)象沒有實(shí)例化,對(duì)類加鎖(一個(gè)線程持有鎖,但這是不知道是否實(shí)例化),所以要再判斷是否實(shí)例化,沒有實(shí)例化進(jìn)行實(shí)例化,實(shí)例化了就返回對(duì)象,這里volatile就是要確保實(shí)例化正確。文章來源地址http://www.zghlxwxcb.cn/news/detail-434314.html

到了這里,關(guān)于【多線程基礎(chǔ)】 線程安全及解決方案(看這一篇就夠了)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Kafka重復(fù)消費(fèi)以及消費(fèi)線程安全關(guān)閉的解決方案

    Kafka消費(fèi)程序每次重啟都會(huì)出現(xiàn)重復(fù)消費(fèi)的情況,考慮是在kill掉程序的時(shí)候,有部分消費(fèi)完的數(shù)據(jù)沒有提交offsect。 此處表明自動(dòng)提交,即延遲提交(poll的時(shí)候會(huì)根據(jù)配置的自動(dòng)提交時(shí)間間隔去進(jìn)行檢測(cè)并提交)。當(dāng)kill掉程序的時(shí)候,可能消費(fèi)完的數(shù)據(jù)還沒有到達(dá)提交的時(shí)間

    2024年02月13日
    瀏覽(22)
  • 【JavaEE面試題(九)線程安全問題的原因和解決方案】

    【JavaEE面試題(九)線程安全問題的原因和解決方案】

    大家觀察下是否適用多線程的現(xiàn)象是否一致?同時(shí)嘗試思考下為什么會(huì)有這樣的現(xiàn)象發(fā)生呢? 原因是 1.load 2. add 3. save 注意:可能會(huì)導(dǎo)致 小于5w 想給出一個(gè)線程安全的確切定義是復(fù)雜的,但我們可以這樣認(rèn)為: 如果多線程環(huán)境下代碼運(yùn)行的結(jié)果是符合我們預(yù)期的,即在單線

    2024年02月16日
    瀏覽(21)
  • 精通線程池,看這一篇就夠了

    精通線程池,看這一篇就夠了

    當(dāng)我們運(yùn)用多線程技術(shù)處理任務(wù)時(shí),需要不斷通過new的方式創(chuàng)建線程,這樣頻繁創(chuàng)建和銷毀線程,會(huì)造成cpu消耗過多。那么有沒有什么辦法 避免頻繁創(chuàng)建線程 呢? 當(dāng)然有,和我們以前學(xué)習(xí)過多連接池技術(shù)類似,線程池通過提前創(chuàng)建好線程保存在線程池中, 在任務(wù)要執(zhí)行時(shí)取

    2023年04月17日
    瀏覽(97)
  • 【多線程】| 線程沖突解決方案

    【多線程】| 線程沖突解決方案

    同一進(jìn)程內(nèi)的線程是共享同一內(nèi)存空間的,所以在多個(gè)線程的進(jìn)程里,線程是可以同時(shí)操作這個(gè)進(jìn)程空間的數(shù)據(jù)的,這樣就容易造成線程沖突的情況。 舉個(gè)小李子:一個(gè)房子里(代表一個(gè)進(jìn)程),只有一個(gè)廁所(代表一個(gè)資源)。屋子里面有兩個(gè)人A和B(代表兩個(gè)線程),共

    2024年02月05日
    瀏覽(92)
  • 了解5G安全標(biāo)準(zhǔn),看這一篇就夠了

    了解5G安全標(biāo)準(zhǔn),看這一篇就夠了

    隨著移動(dòng)通信系統(tǒng)在社會(huì)生活中的使用越來越廣泛,特別是5G進(jìn)一步以企業(yè)級(jí)應(yīng)用作為核心應(yīng)用場(chǎng)景,安全成為了包括5G在內(nèi)的移動(dòng)通信系統(tǒng)不可忽視的因素。本文梳理了全球主流移動(dòng)通信標(biāo)準(zhǔn)化組織在安全方面的標(biāo)準(zhǔn)制定,從而可以快速了解5G協(xié)議層面對(duì)信息安全的考量。原

    2024年02月05日
    瀏覽(28)
  • CSS基礎(chǔ)——看這一篇就夠了

    CSS基礎(chǔ)——看這一篇就夠了

    目錄 一、CSS簡介 1.CSS是什么? 2.CSS的作用 3.CSS的構(gòu)成 二、CSS選擇器 1.基礎(chǔ)選擇器 (1).標(biāo)簽選擇器 (2)類選擇器 (3)標(biāo)簽選擇器 (4) 通配符選擇器 2.復(fù)合選擇器 (1)后代選擇器(包含選擇器) (2)子選擇器 (3)并集選擇器 (4)偽類選擇器 ?三、基本屬性 1.字體屬性

    2024年02月09日
    瀏覽(98)
  • @Async異步線程:Spring 自帶的異步解決方案

    @Async異步線程:Spring 自帶的異步解決方案

    ? ? ? ? 在項(xiàng)目應(yīng)用中,使用MQ異步調(diào)用來實(shí)現(xiàn)系統(tǒng)性能優(yōu)化,完成服務(wù)間數(shù)據(jù)同步是常用的技術(shù)手段。如果是在同一臺(tái)服務(wù)器內(nèi)部,不涉及到分布式系統(tǒng),單純的想實(shí)現(xiàn)部分業(yè)務(wù)的異步執(zhí)行,這里介紹一個(gè)更簡單的異步方法調(diào)用。 ????????對(duì)于異步方法調(diào)用,從Spring3 開

    2023年04月24日
    瀏覽(24)
  • 前端HTML基礎(chǔ):表單標(biāo)簽看這一篇就行了。

    表單標(biāo)簽: ?? ?在網(wǎng)頁中為了收集用戶資料,此時(shí)你就會(huì)用到表單。 在HTML中,一個(gè)完整的表單由表單域、表單控件和提示信息3個(gè)部分組成 1.表單域 表單域就是一個(gè)包含表單元素的區(qū)域。 在HTML標(biāo)簽中,form標(biāo)簽用于定義表單域,以實(shí)現(xiàn)用戶信息的收集和傳遞。 form會(huì)把它范

    2024年02月21日
    瀏覽(20)
  • 【Linux】shell編程基礎(chǔ)(超詳細(xì),入門看這一篇就夠了)

    【Linux】shell編程基礎(chǔ)(超詳細(xì),入門看這一篇就夠了)

    ????【Liunx學(xué)習(xí)記錄篇】???? 篇一:【Linux】VMware安裝unbuntu18.04虛擬機(jī)-超詳細(xì)步驟(附鏡像文件) 篇二:【Linux】ubuntu18.04系統(tǒng)基礎(chǔ)配置及操作 篇三:【Linux】用戶與組的操作詳細(xì)介紹 篇四:【Linux】管理Linux文件權(quán)限屬性介紹 篇五:【Linux】使用數(shù)字表示法和文件表示法修

    2024年02月04日
    瀏覽(41)
  • 安全網(wǎng)格:數(shù)據(jù)安全的終極解決方案

    隨著網(wǎng)絡(luò)威脅的不斷增長和安全法規(guī)的日益嚴(yán)苛,全球網(wǎng)絡(luò)安全投資規(guī)模不斷創(chuàng)下新高。據(jù)Gartner預(yù)測(cè),2024年全球組織在IT安全和風(fēng)險(xiǎn)管理工具上的投入將達(dá)到2087億美元。 然而,埃森哲(Accenture)的報(bào)告卻顯示,盡管投入巨資,超過七成(74%)的首席執(zhí)行官對(duì)企業(yè)數(shù)據(jù)安全和網(wǎng)

    2024年04月27日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包