中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

給網(wǎng)站劃分欄目怎么做百度關(guān)鍵詞排名

給網(wǎng)站劃分欄目,怎么做百度關(guān)鍵詞排名,wordpress郵件通知代碼,自己設(shè)計(jì)服裝的app免費(fèi)volatile 關(guān)鍵字 volatile 能保證內(nèi)存可見性 volatile 修飾的變量, 能夠保證 “內(nèi)存可見性” 示例代碼: 運(yùn)行結(jié)果: 當(dāng)輸入1(1是非O)的時(shí)候,但是t1這個(gè)線程并沿有結(jié)束循環(huán), 同時(shí)可以看到,t2這個(gè)線程已經(jīng)執(zhí)行完了,而t1線程還在繼續(xù)循環(huán). 這個(gè)情況,就叫做內(nèi)存可見性問題 ~~ 這…

請(qǐng)?zhí)砑訄D片描述

volatile 關(guān)鍵字

volatile 能保證內(nèi)存可見性
volatile 修飾的變量, 能夠保證 “內(nèi)存可見性”

示例代碼:

image-20230927234356426

運(yùn)行結(jié)果:
image-20230927234904570

當(dāng)輸入1(1是非O)的時(shí)候,但是t1這個(gè)線程并沿有結(jié)束循環(huán),
同時(shí)可以看到,t2這個(gè)線程已經(jīng)執(zhí)行完了,而t1線程還在繼續(xù)循環(huán).

這個(gè)情況,就叫做內(nèi)存可見性問題 ~~ 這也是一個(gè)線程不安全問題(一個(gè)線程讀,一個(gè)線程改)

while (myCounter.flag == 0) { // 循環(huán)體空著,什么也不做 }

這里使用匯編來理解,大概就是兩步操作:

  1. load, 把內(nèi)存中 flag 的值,讀取到寄存器里.
  2. cmp, 把寄存器的值,和0進(jìn)行比較,根據(jù)比較結(jié)果,決定下一步往哪個(gè)地方執(zhí)行(條件跳轉(zhuǎn)指令).

上述是個(gè)循環(huán),這個(gè)循環(huán)執(zhí)行速度極快,一秒鐘執(zhí)行百萬(wàn)次以上…
循環(huán)執(zhí)行這么多次,在線程 t2 真正修改之前, load得到的結(jié)果都是一樣的;
另一方面, load操作和cmp操作相比,速度慢非常非常多!!!

注:
CPU針對(duì)寄存器的操作,要比內(nèi)存操作快很多,快3-4數(shù)量級(jí);
計(jì)算機(jī)對(duì)于內(nèi)存的操作,比硬盤快3-4個(gè)數(shù)量級(jí).

由于 load 執(zhí)行速度太慢(相比于cmp來說),再加上反復(fù) load 到的結(jié)果都一樣, JVM 就做出了一個(gè)非常大膽的決定 ~~ 判定好像沒人改 flag 值,不再真正的重復(fù) load 了,干脆就只讀取一次就好了 => 編譯器優(yōu)化的一種方式.
實(shí)際上是有人在修改的,但是 JVM/編譯器 對(duì)于這種多線程的情況,判定可能存在誤差.
此時(shí),就需要我們手動(dòng)干預(yù)了,可以給 flag 這個(gè)變量加上 volatile 關(guān)鍵字,意思就是告訴編譯器,這個(gè)變量是"易變"的,要每次都重新讀取這個(gè)變量的內(nèi)存內(nèi)容,不能再進(jìn)行激進(jìn)的優(yōu)化了.
博主感慨: 快和準(zhǔn)之間往往不可兼得

內(nèi)存可見性問題

一個(gè)線程針對(duì)一個(gè)變量進(jìn)行讀取操作,同時(shí)另一個(gè)線程針對(duì)這個(gè)變量進(jìn)行修改,此時(shí)讀到的值,不一定是修改之后的值;這個(gè)讀線程沒有感知到變量的變化;
歸根結(jié)底是 編譯器/JVM 在多線程環(huán)境下優(yōu)化時(shí)產(chǎn)生了誤判了.
備注:
(1)上述說的內(nèi)存可見性編譯器優(yōu)化的問題,也不是始終會(huì)出現(xiàn)的(編譯器可能存在誤判,也不是100%就誤判!);
(2)編譯器的優(yōu)化,很多時(shí)候是“玄學(xué)問題”,應(yīng)用程序這個(gè)角度是無(wú)法感知的.編譯器的優(yōu)化,很多時(shí)候是“玄學(xué)問題”,應(yīng)用程序這個(gè)角度是無(wú)法感知的.

代碼改正:

class MyCounter {volatile public int flag = 0;
}

運(yùn)行結(jié)果:

image-20230928004924362

注意事項(xiàng):
(1) volatile 只能修飾變量;
(2) volatile 不能修飾方法的局部變量,局部變量只能在你當(dāng)前線程里面用,不能多線程之間同時(shí)讀取/修改(天然就規(guī)避了線程安全問題);

(1)局部變量只能在當(dāng)前方法里使用的,出了方法變量就沒了,方法內(nèi)部的變量在"?!边@樣的內(nèi)存空間上;
(2)每個(gè)線程都有自己的??臻g,即使是同一個(gè)方法,在多個(gè)線程中被調(diào)用,這里的局部變量也會(huì)處在不同的棧空間中,本質(zhì)上是不同變量,也就涉及不到修改/讀取同一個(gè)變量的操作;
(3)棧記錄了方法之間的調(diào)用關(guān)系;
個(gè)人理解: 局部變量只對(duì)當(dāng)前線程可見,其他線程看不了.

(3) 如果一個(gè)變量在兩個(gè)線程中,一個(gè)讀,一個(gè)寫,就需要考慮volatile 了;
(4) volatile 不保證原子性,原子性是靠 synchronized 來保證的. synchronized 和 volatile 都能保證線程安全 => 不能使用 volatile 處理兩個(gè)線程并發(fā)++這樣的問題;
(5) 如果涉及到某個(gè)代碼,既需要考慮原子性,有需要考慮內(nèi)存可見性,就把 synchronized 和 volatile 都用上就行了.


從 JMM 的角度重新表述內(nèi)存可見性問題

內(nèi)存可見性問題,其他的一些資料,談到了JMM(Java Memory Mode ~~ Java內(nèi)存模型)
從 JMM 的角度重新表述內(nèi)存可見性問題(Java的官方文檔的大概表述):
Java 程序里,主內(nèi)存,每個(gè)線程還有自己的工作內(nèi)存(線程 t1 的和線程 t2 的工作內(nèi)存不是同一個(gè)東西);
線程 t1 進(jìn)行讀取的時(shí)候,只是讀取了工作內(nèi)存的值;
線程 t2進(jìn)行修改的時(shí)候,先修改的工作內(nèi)存的值,然后再把工作內(nèi)存的內(nèi)容同步到主內(nèi)存中,但是由于編譯器優(yōu)化,導(dǎo)致線程 t1沒有重新的從主內(nèi)存同步數(shù)據(jù)到工作內(nèi)存,讀到的結(jié)果就是“修改之前"的結(jié)果.

如果把"主內(nèi)存”代替成"內(nèi)存",把“工作內(nèi)存"代替成"CPU寄存器",就容易理解.
注: 之所以上面這段話這么晦澀,是翻譯不行,翻譯官得背鍋 ~~ 翻譯的結(jié)果讓人誤會(huì)了!!!
主內(nèi)存: main memory => 主存,也就是平時(shí)所說的內(nèi)存
工作內(nèi)存: work memory =>工作存儲(chǔ)區(qū),并非是所說的內(nèi)存,而是CPU上存儲(chǔ)數(shù)據(jù)的單元(寄存器)

為什么Java這里,不直接叫做“CPU寄存器",而是專門搞了"工作內(nèi)存”說法呢?

這里的工作內(nèi)存,不一定只是CPU的寄存器,還可能包括CPU的緩存cache.

image-20230928013620585

當(dāng)CPU要讀取一個(gè)內(nèi)存數(shù)據(jù)的時(shí)候,可能是直接讀內(nèi)存也可能是讀cache還能是讀寄存器…
引入cache之后,硬件結(jié)構(gòu)就更復(fù)雜了,工作內(nèi)存(工作存儲(chǔ)區(qū)): CPU寄存器 + CPU的cache;
一方面是為了表述簡(jiǎn)單,另一方面也是為了避免涉及到硬件的細(xì)節(jié)和差異,Java里就使用"工作內(nèi)存"這個(gè)詞來統(tǒng)稱(泛指)了;畢竟,現(xiàn)實(shí)中有的 CPU 可能沒有 cache, 有的 CPU 有;有的 CPU 可能有一個(gè)cache,還可能有多個(gè);現(xiàn)代的 CPU 普遍是3級(jí)cache, L1, L2, L3,總之,情況多樣.
注: 學(xué)校的"計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)”會(huì)講解CPU內(nèi)部的結(jié)構(gòu),尤其是寄存器, cache,指令等等,上這門課的時(shí)候要好好聽講.

wait 和 notify

線程最大的問題,是搶占式執(zhí)行,隨機(jī)調(diào)度~~
程序猿寫代碼,不喜歡隨機(jī),喜歡確定的東西,于是發(fā)明了一些辦法,來控制線程之間的執(zhí)行順序,雖然線程在內(nèi)核里的調(diào)度是隨機(jī)的,但是可以通過一些 API 讓線程主動(dòng)塞,主動(dòng)放棄CPU(給別的線程讓路).
比如,t1,t2 兩個(gè)線程,希望t1先干活,干的差不多了,再讓t2來干.就可以讓t2先wait(阻塞,主動(dòng)放棄CPU)等t1干的差不多了,再通過notify 通知t2,把t2喚醒,讓t2接著干.

那么上述場(chǎng)景,使用 join 或者 sleep行不行呢?

使用join,則必須要t1徹底執(zhí)行完,t2才能運(yùn)行.如果是希望t1先干50%的活,就讓t2開始行動(dòng),join無(wú)能為力.
使用sleep,指定一個(gè)休眠時(shí)間的,但是t1執(zhí)行的這些活,到底花了多少時(shí)間,不好估計(jì).
使用wait和notify可以更好的解決上述的問題.

注: wait, notify, notifyAll 這幾個(gè)類,都是Object類(Java里所有類的祖宗)的方法.Java里隨便new個(gè)對(duì)象,都可以有這三個(gè)方法!!

wait

wait 進(jìn)行阻塞.某個(gè)線程調(diào)用wait方法,就會(huì)進(jìn)入阻塞(無(wú)論是通過哪個(gè)對(duì)象 wait的),此時(shí)就處在WAITING狀態(tài).
wait 不加任何參數(shù),就是一個(gè)"死等"一直等待,直到有其它線程喚醒它.
示例代碼:

public class ThreadDemo16 {public static void main(String[] args) throws InterruptedException {Object object = new Object();object.wait();}
}

throws InterruptedException : 這個(gè)異常,很多帶有阻塞功能的方法都帶.這些方法都是可以 interrupt 方法通過這個(gè)異常給喚醒的.

運(yùn)行結(jié)果:

image-20230927204141554

IllegalMonitorStateException
~~ 非法的鎖狀態(tài)異常
~~ 鎖的狀態(tài),無(wú)非就是被加鎖的狀態(tài)和和被解鎖的狀態(tài).

為什么有這個(gè)異常,要先理解 wait 的操作是干什么了.
1.先釋放鎖
2.進(jìn)行阻塞等待
3.收到通知之后,重新嘗試獲取鎖,并且在獲取鎖后,繼續(xù)往下執(zhí)行.

這里鎖狀態(tài)異常,就是沒加鎖呢,就想著釋放鎖.就好比單身著呢,就想著分手.

public static void main(String[] args) throws InterruptedException {Object object = new Object();synchronized (object) {System.out.println("wait 之前");object.wait();System.out.println("wait 之后");}}

image-20230927205029017

雖然這里wait是阻塞了,阻塞在 synchronized 代碼塊里,實(shí)際上,這里的阻塞是釋放了鎖的,此時(shí)其他線程是可以獲取到object這個(gè)對(duì)象的鎖的,此時(shí)這里的阻塞,就處在WAITING狀態(tài).

image-20230928094946950

t1.start();
t2.start();

如果代碼這里寫作 t1.start 和 t2.start 由于線程調(diào)度的不確定性,此時(shí)不能保證一定是先執(zhí)行 wait ,后執(zhí)行notify. 如果調(diào)用notify,此時(shí)沒有線程wait,此處的wait是無(wú)法被喚醒的!!!(這種通知就是無(wú)效通知).
因此此處的代碼還是要盡量保證先執(zhí)行wait后執(zhí)行notify才是有意義的.

改正的代碼:

   public static void main(String[] args) throws InterruptedException {Object object = new Object();Thread t1 = new Thread(() -> {// 這個(gè)線程負(fù)責(zé)進(jìn)行等待System.out.println("t1: wait 之前");try {synchronized (object) {object.wait();}} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t2: wait 之后");});Thread t2 = new Thread(() -> {System.out.println("t2: notify 之前");synchronized (object) {// notify 務(wù)必要獲取到鎖,才能進(jìn)行通知object.notify();}System.out.println("t2: notify 之后");});t1.start();// 此處寫的 sleep 500 是大概率會(huì)讓 t1 先執(zhí)行 wait 的// 極端情況下,電腦特別卡的時(shí)候, 可能線程的調(diào)度時(shí)間就超過了 500 ms// 還是可能 t2 先執(zhí)行 notifyThread.sleep(500);t2.start();}

運(yùn)行結(jié)果:

image-20230927214510375

此處,先執(zhí)行了wait,很明顯wait操作阻塞了,沒有看到wait之后的打印;
接下來執(zhí)行到了t2, t2進(jìn)行了notify的時(shí)候,才會(huì)把t1的wait喚醒.t1才能繼續(xù)執(zhí)行.
只要t2不進(jìn)行notify,此時(shí)t1就會(huì)始終wait下去(死等).

wait無(wú)參數(shù)版本,就是死等的.
wait帶參數(shù)版本,指定了等待的最大時(shí)間.

wait的帶有等待時(shí)間的版本,看起來就和sleep有點(diǎn)像.其實(shí)還是有本質(zhì)差別的:
雖然都是能指定等待時(shí)間,也都能被提前喚醒(wait是使用notify 喚醒, sleep使用interrupt喚醒)但是這里表示的含義截然不同.
notify喚醒wait,這是不會(huì)有任何異常的.(正常的業(yè)務(wù)邏輯),interrupt喚醒sleep 則是出異常了(表示一個(gè)出問題了的邏輯).

如果當(dāng)前有多個(gè)線程在等待object對(duì)象,此時(shí)有一個(gè)線程 object.notify(),此時(shí)是隨機(jī)喚醒一個(gè)等待的線程.(不知道具體是哪個(gè)),但是,可以用多組不同的對(duì)象來控制線程的執(zhí)行順序.
比如,有三個(gè)線程,希望先執(zhí)行線程1,再執(zhí)行線程2,再執(zhí)行線程3,
創(chuàng)建obj1,供線程1,2使用創(chuàng)建obj2,供線程2,3使用線程3, obj2.wait
線程2.obj1.wait(),喚醒之后執(zhí)行obj2.notify()
線程1執(zhí)行自己的任務(wù),執(zhí)行完了之后,obj1.notify即可.

notifyAll和notify非常相似.
多個(gè)線程 wait 的時(shí)候, notify隨機(jī)喚醒一個(gè), notifyAll 所有線程都喚醒,這些線程再一起競(jìng)爭(zhēng)鎖…

http://www.risenshineclean.com/news/31519.html

相關(guān)文章:

  • 做網(wǎng)站用什么框架好怎么引流怎么推廣自己的產(chǎn)品
  • 公司網(wǎng)站郵箱費(fèi)用熱搜詞排行榜關(guān)鍵詞
  • 鄭州建站價(jià)格手機(jī)百度app下載安裝
  • Wordpress 視頻采集插件電商seo優(yōu)化是什么意思
  • 漳州微網(wǎng)站建設(shè)公司推薦百度廣告聯(lián)系方式
  • 網(wǎng)站建設(shè)多長(zhǎng)時(shí)間能學(xué)會(huì)做網(wǎng)站平臺(tái)需要多少錢
  • 怎么查詢網(wǎng)站備案培訓(xùn)學(xué)校怎么招生
  • 如何做直播做菜視頻網(wǎng)站關(guān)鍵詞優(yōu)化排名
  • 西鄉(xiāng)網(wǎng)站開發(fā)長(zhǎng)沙seo關(guān)鍵詞排名
  • 工藝品做網(wǎng)站網(wǎng)絡(luò)推廣公司
  • wordpress指定用戶隱藏分類廣州seo站內(nèi)優(yōu)化
  • 鄭州做網(wǎng)站推廣價(jià)格徐州seo排名收費(fèi)
  • 廣州網(wǎng)站設(shè)計(jì)出名 樂云踐新正規(guī)推廣平臺(tái)有哪些
  • 外貿(mào)手機(jī)網(wǎng)站seo標(biāo)題優(yōu)化的心得總結(jié)
  • 網(wǎng)站設(shè)計(jì)實(shí)例搜狗快速收錄方法
  • 沒有照片怎么做網(wǎng)站教育培訓(xùn)網(wǎng)站大全
  • 廣西住房建設(shè)廳網(wǎng)站搜索引擎營(yíng)銷案例分析題
  • 西安住房和城鄉(xiāng)建設(shè)局網(wǎng)站如何讓自己的網(wǎng)站快速被百度收錄
  • 政府網(wǎng)站內(nèi)容建設(shè)方案怎么免費(fèi)注冊(cè)域名
  • 保定網(wǎng)站定制公司seo少女
  • 建站廣告?zhèn)€人網(wǎng)站首頁(yè)設(shè)計(jì)
  • 邢臺(tái)企業(yè)做網(wǎng)站費(fèi)用哪里可以建網(wǎng)站
  • 瑞麗網(wǎng)站建設(shè)深圳整站seo
  • 湖南做網(wǎng)站 真好磐石網(wǎng)絡(luò)東莞公司網(wǎng)上推廣
  • 網(wǎng)站建設(shè)銷售發(fā)展前景百度指數(shù)關(guān)鍵詞搜索趨勢(shì)
  • 英文seo公司seo文章
  • 網(wǎng)站域名使用期怎么去推廣自己的店鋪
  • 做ar的網(wǎng)站搜資源的搜索引擎
  • 婦聯(lián)網(wǎng)站建設(shè)方案搜索歷史記錄
  • 熟人做網(wǎng)站怎么收錢湖南seo服務(wù)電話