最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Java 并發(fā)編程面試題(1)

2023-02-21 18:32 作者:茶曉i  | 我要投稿

一、原子性高頻問(wèn)題:

1.1 ?Java中如何實(shí)現(xiàn)線(xiàn)程安全?

多線(xiàn)程操作共享數(shù)據(jù)出現(xiàn)的問(wèn)題。

鎖:

  • 悲觀(guān)鎖:synchronized,lock

  • 樂(lè)觀(guān)鎖:CAS

可以根據(jù)業(yè)務(wù)情況,選擇ThreadLocal,讓每個(gè)線(xiàn)程玩自己的數(shù)據(jù)。

1.2 CAS底層實(shí)現(xiàn)

最終回答:先從比較和交換的角度去聊清楚,在Java端聊到native方法,然后再聊到C++中的cmpxchg的指令,再聊到lock指令保證cmpxchg原子性

Java的角度,CAS在Java層面最多你就能看到native方法。

你會(huì)知道比較和交換:

  • 先比較一下值是否與預(yù)期值一致,如果一致,交換,返回true

  • 先比較一下值是否與預(yù)期值一致,如果不一致,不交換,返回false

可以去看Unsafe類(lèi)中提供的CAS操作

四個(gè)參數(shù):哪個(gè)對(duì)象,哪個(gè)屬性的內(nèi)存偏移量,oldValue,newValue

image.png

native是直接調(diào)用本地依賴(lài)庫(kù)C++中的方法。

https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/share/vm/prims/unsafe.cpp

image.png

https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp

在CAS底層,如果是多核的操作系統(tǒng),需要追加一個(gè)lock指令

單核不需要加,因?yàn)閏mpxchg是一行指令,不能再被拆分了

image.png

看到cmpxchg ,是匯編的指令,CPU硬件底層就支持 比較和交換 (cmpxchg),cmpxchg并不保證原子性的。(cmpxchg的操作是不能再拆分的指令)

所以才會(huì)出現(xiàn)判斷CPU是否是多核,如果是多核就追加lock指令。

lock指令你可以理解為是CPU層面的鎖,一般鎖的粒度就是 緩存行 級(jí)別的鎖,當(dāng)然也有 總線(xiàn)鎖 ,但是成本太高,CPU會(huì)根據(jù)情況選擇。

1.3 CAS的常見(jiàn)問(wèn)題

ABA: ABA不一定是問(wèn)題!因?yàn)橐恍┲淮嬖?++,--的這種操作,即便出現(xiàn)ABA問(wèn)題,也不影響結(jié)果!

線(xiàn)程A:期望將value從A1 - B2

線(xiàn)程B:期望將value從B2 - A3

線(xiàn)程C:期望將value從A1 - C4

按照原子性來(lái)說(shuō),無(wú)法保證線(xiàn)程安全。

解決方案很簡(jiǎn)單,Java端已經(jīng)提供了。

image.png

說(shuō)人話(huà)就是,在修改value的同時(shí),指定好版本號(hào)。

JUC下提供的AtomicStampedReference就可以實(shí)現(xiàn)。

自旋次數(shù)過(guò)多:

自旋次數(shù)過(guò)多,會(huì)額外的占用大量的CPU資源!浪費(fèi)資源。

回答方式:可以從synchronized或者LongAdder層面去聊

  • synchronized方向:從CAS幾次失敗后,就將線(xiàn)程掛起(WAITING),避免占用CPU過(guò)多的資源!

  • LongAdder方向:這里是基于類(lèi)似 分段鎖 的形式去解決(要看業(yè)務(wù),有限制的),傳統(tǒng)的AtmoicLong是針對(duì)內(nèi)存中唯一的一個(gè)值去++,LongAdder在內(nèi)存中搞了好多個(gè)值,多個(gè)線(xiàn)程去加不同的值,當(dāng)你需要結(jié)果時(shí),我將所有值累加,返回給你。

只針對(duì)一個(gè)屬性保證原子性: 處理方案,學(xué)了AQS就懂了。ReentrantLock基于A(yíng)QS實(shí)現(xiàn),AQS基于CAS實(shí)現(xiàn)核心功能。

1.4 四種引用類(lèi)型 + ThreadLocal的問(wèn)題?

ThreadLocal的問(wèn)題:Java基礎(chǔ)面試題2 -- 第16題。

四種引用類(lèi)型:

  • 強(qiáng)引用:User xx = new User(); ?xx就是強(qiáng)引用,只要引用還在,GC就不會(huì)回收!

  • 軟引用:用一個(gè)SofeReference引用的對(duì)象,就是軟引用,如果內(nèi)存空間不足,才會(huì)回收只有軟引用指向?qū)ο蟆?一般用于做緩存。

    SoftwareReference xx = new SoftwareReference (new User);

    User user = xx.get();
  • 弱引用:WeakReference引用的對(duì)象,一般就是弱引用,只要執(zhí)行GC,就會(huì)回收只有弱引用指向的對(duì)象。可以解決內(nèi)存泄漏的問(wèn)題 ,看ThreadLocal即可

    ThreadLocal的問(wèn)題:Java基礎(chǔ)面試題2 -- 第16題。

  • 虛引用:PhantomReference引用的對(duì)象,就是虛引用,拿不到虛引用指向的對(duì)象,一般監(jiān)聽(tīng)GC回收階段,或者是回收堆外內(nèi)存時(shí)使用。

二、可見(jiàn)行高頻問(wèn)題:

2.1 Java的內(nèi)存模型

回答方式。先全局描述。 在處理指令時(shí),CPU會(huì)拉取數(shù)據(jù),優(yōu)先級(jí)是從L1到L2到L3,如果都沒(méi)有,需要去主內(nèi)存中拉取,JMM就是在CPU和主內(nèi)存之間,來(lái)協(xié)調(diào),保證可見(jiàn)、有序性等操作。

一定要聊JMM,別上來(lái)就聊JVM的內(nèi)存結(jié)構(gòu),不是一個(gè)東西?。。。。↗ava Memory Model)

image.png

、

CPU核心,就是CPU核心(寄存器)

緩存是CPU的緩存,CPU的緩存分為L(zhǎng)1(線(xiàn)程獨(dú)享),L2(內(nèi)核獨(dú)享),L3(多核共享)

JMM就是Java內(nèi)存模型的核心,可見(jiàn)性,有序性都基于這實(shí)現(xiàn)。

主內(nèi)存JVM,就是你堆內(nèi)存。

2.2 保證可見(jiàn)性的方式

啥是可見(jiàn)性: 可見(jiàn)性是指線(xiàn)程間的,對(duì)變量的變化是否可見(jiàn)

Java層面中,保證可見(jiàn)性的方式有很多:

  • volatile,用volatile基本數(shù)據(jù)類(lèi)型,可以保證每次CPU去操作數(shù)據(jù)時(shí),都直接去主內(nèi)存進(jìn)行讀寫(xiě)。

  • synchronized,synchronized的內(nèi)存語(yǔ)義可以保證在獲取鎖之后,可以保證前面操作的數(shù)據(jù)是可見(jiàn)的。

  • lock(CAS-volatile),也可以保證CAS或者操作volatile的變量之后,可以保證前面操作的數(shù)據(jù)是可見(jiàn)的。

  • final,是常量沒(méi)法動(dòng)~~

2.3 volatile修飾引用數(shù)據(jù)類(lèi)型

先說(shuō)結(jié)果, 首先volatile修飾引用數(shù)據(jù)類(lèi)型,只能保證引用數(shù)據(jù)類(lèi)型的地址是可見(jiàn)的,不保證內(nèi)部屬性可見(jiàn)。

But,這個(gè)結(jié)論只能在hotspot中實(shí)現(xiàn),如果換一個(gè)版本的虛擬機(jī),可能效果就不一樣了。volatile修飾引用數(shù)據(jù)類(lèi)型,JVM壓根就沒(méi)規(guī)范過(guò)這種操作,不同的虛擬機(jī)廠(chǎng)商,可以自己實(shí)現(xiàn)。 這個(gè)問(wèn)題,只出現(xiàn)在面試中,干活你要這么干……………………干丫的~

2.4 有了MESI協(xié)議,為啥還有volatile?

MESI是CPU緩存一致性的協(xié)議,大多數(shù)的CPU廠(chǎng)商都根據(jù)MESI去實(shí)現(xiàn)了緩存一致性的效果。

CPU已經(jīng)有MESI協(xié)議了,volatile是不是有點(diǎn)多余?。??

首先,這哥倆不沖突,一個(gè)是從CPU硬件層面上的一致性,一個(gè)是Java中JMM層面的一致性。

MESI協(xié)議,他有一套固定的機(jī)制,無(wú)論你是否聲明了volatile,他都會(huì)基于這個(gè)機(jī)制來(lái)保證緩存的一致性(可見(jiàn)性)。同時(shí),也要清楚,如果沒(méi)有MESI協(xié)議,volatile也會(huì)存在一些問(wèn)題,不過(guò)也有其他的處理方案(總線(xiàn)鎖,時(shí)間成本太高了,如果鎖了總線(xiàn),就一個(gè)CPU核心在干活)。

MESI是協(xié)議,是規(guī)劃,是interface,他需要CPU廠(chǎng)商實(shí)現(xiàn)。

既然CPU有MESI了,為啥還要volatile,那自然是MESI協(xié)議有問(wèn)題。MESI保證了多核CPU的獨(dú)占cache之間的可見(jiàn)性,但是CPU不是說(shuō)必須直接將寄存器中的數(shù)據(jù)寫(xiě)入到L1,因?yàn)樵诖蠖嗍恰?6架構(gòu)的CPU中,寄存器和L1之間有一個(gè)store buffer,寄存器值可能落到了store buffer,沒(méi)落到L1中,就會(huì)導(dǎo)致緩存不一致。而且除了×86架構(gòu)的CPU,在arm和power的CPU中,還有l(wèi)oad buffer,invalid queue都會(huì)或多或少影響緩存一致性!

回答的方式:MESI協(xié)議和volatile不沖突,因?yàn)镸ESI是CPU層面的,而CPU廠(chǎng)商很多實(shí)現(xiàn)不一樣,而且CPU的架構(gòu)中的一些細(xì)節(jié)也會(huì)有影響,比如Store Buffer會(huì)影響寄存器寫(xiě)入L1緩存,導(dǎo)致緩存不一致。volatile的底層生成的是匯編的lock指令,這個(gè)指令會(huì)要求強(qiáng)行寫(xiě)入主內(nèi)存,并且可以忽略Store Buffer這種緩存從而達(dá)到可見(jiàn)性的目的,而且會(huì)利用MESI協(xié)議,讓其他緩存行失效。

2.5 volatile的可見(jiàn)性底層實(shí)現(xiàn)

volatile的底層生成的是匯編的lock指令,這個(gè)指令會(huì)要求強(qiáng)行寫(xiě)入主內(nèi)存,并且可以忽略Store Buffer這種緩存從而達(dá)到可見(jiàn)性的目的,而且會(huì)利用MESI協(xié)議,讓其他緩存行失效。

三、有序性高頻問(wèn)題:

3.1 什么是有序性問(wèn)題

單例模式中的懶漢機(jī)制中,就存在一個(gè)這樣的問(wèn)題。

懶漢為了保證線(xiàn)程安全,一般會(huì)采用DCL的方式。

但是單單用DCL,依然會(huì)有幾率出現(xiàn)問(wèn)題。

線(xiàn)程可能會(huì)拿到初始化一半的對(duì)象去操作,極有可能出現(xiàn)NullPointException。

(初始化對(duì)象三部,開(kāi)辟空間,初始化內(nèi)部屬性,指針指向引用)

在Java編譯.java為.class時(shí),會(huì)基于JIT做優(yōu)化,將指令的順序做調(diào)整,從而提升執(zhí)行效率。

在CPU層面,也會(huì)對(duì)一些執(zhí)行進(jìn)行重新排序,從而提升執(zhí)行效率。

這種指令的調(diào)整,在一些特殊的操作上,會(huì)導(dǎo)致出現(xiàn)問(wèn)題。

3.2 volatile的有序性底層實(shí)現(xiàn)

被volatile修飾的屬性,在編譯時(shí),會(huì)在前后追加 內(nèi)存屏障 。

SS:屏障前的讀寫(xiě)操作,必須全部完成,再執(zhí)行后續(xù)操作

SL:屏障前的寫(xiě)操作,必須全部完成,再執(zhí)行后續(xù)讀操作

LL:屏障前的讀操作,必須全部完成,再執(zhí)行后續(xù)讀操作

LS:屏障前的讀操作,必須全部完成,再執(zhí)行后續(xù)寫(xiě)操作

image.png

這個(gè)內(nèi)存屏障是JDK規(guī)定的,目的是保證volatile修飾的屬性不會(huì)出現(xiàn)指令重排的問(wèn)題。

volatile在JMM層面,保證JIT不重排可以理解,但是,CPU怎么實(shí)現(xiàn)的。

查看這個(gè)文檔:https://gee.cs.oswego.edu/dl/jmm/cookbook.html

image.png

不同的CPU對(duì)內(nèi)存屏障都有一定的支持,比如×86架構(gòu),內(nèi)部自己已經(jīng)實(shí)現(xiàn)了LS,LL,SS,只針對(duì)SL做了支持。

去openJDK再次查看,mfence是如何支持的。其實(shí)在底層還是mfence內(nèi)部的lock指定,來(lái)解決指令重排問(wèn)題。

image.png

四、synchronized高頻問(wèn)題:

4.1 synchronized鎖升級(jí)的過(guò)程?

鎖就是對(duì)象,隨便哪一個(gè)都可以,Java中所有對(duì)象都是鎖。

無(wú)鎖(匿名偏向)、偏向鎖、輕量級(jí)鎖、重量級(jí)鎖

無(wú)鎖(匿名偏向): 一般情況下,new出來(lái)的一個(gè)對(duì)象,是無(wú)鎖狀態(tài)。因?yàn)槠蜴i有延遲,在啟動(dòng)JVM的4s中,不存在偏向鎖,但是如果關(guān)閉了偏向鎖延遲的設(shè)置,new出來(lái)的對(duì)象,就是匿名偏向。

偏向鎖: 當(dāng)某一個(gè)線(xiàn)程來(lái)獲取這個(gè)鎖資源時(shí),此時(shí),就會(huì)變?yōu)槠蜴i,偏向鎖存儲(chǔ)線(xiàn)程的ID

當(dāng)偏向鎖升級(jí)時(shí),會(huì)觸發(fā)偏向鎖撤銷(xiāo),偏向鎖撤銷(xiāo)需要等到一個(gè)安全點(diǎn),比如GC的時(shí)候,偏向鎖撤銷(xiāo)的成本太高,所以默認(rèn)開(kāi)始時(shí),會(huì)做偏向鎖延遲。

安全點(diǎn):

  • GC

  • 方法返回之前

  • 調(diào)用某個(gè)方法之后

  • 甩異常的位置

  • 循環(huán)的末尾

輕量級(jí)鎖: 當(dāng)在出現(xiàn)了多個(gè)線(xiàn)程的競(jìng)爭(zhēng),就要升級(jí)為輕量級(jí)鎖(有可能直接從無(wú)鎖變?yōu)檩p量級(jí)鎖,也有可能從偏向鎖升級(jí)為輕量級(jí)鎖),輕量級(jí)鎖的效果就是基于CAS嘗試獲取鎖資源,這里會(huì)用到自適應(yīng)自旋鎖,根據(jù)上次CAS成功與否,決定這次自旋多少次。

重量級(jí)鎖: 如果到了重量級(jí)鎖,那就沒(méi)啥說(shuō)的了,如果有線(xiàn)程持有鎖,其他競(jìng)爭(zhēng)的,就掛起。

4.2 synchronized鎖粗化&鎖消除?

鎖粗化(鎖膨脹):(JIT優(yōu)化)

鎖消除:在一個(gè)sync中,沒(méi)有任何共享資源,也不存在鎖競(jìng)爭(zhēng)的情況,JIT編譯時(shí),就直接將鎖的指令優(yōu)化掉。

4.3 synchronized實(shí)現(xiàn)互斥性的原理?

偏向鎖:查看對(duì)象頭中的MarkWord里的線(xiàn)程ID,是否是當(dāng)前線(xiàn)程,如果不是,就CAS嘗試改,如果是,就拿到了鎖資源。

輕量級(jí)鎖:查看對(duì)象頭中的MarkWord里的Lock Record指針指向的是否是當(dāng)前線(xiàn)程的虛擬機(jī)棧,如果是,拿鎖執(zhí)行業(yè)務(wù),如果不是CAS,嘗試修改,修改他幾次,不成,再升級(jí)到重量級(jí)鎖。

重量級(jí)鎖:查看對(duì)象頭中的MarkWord里的指向的ObjectMonitor,查看owner是否是當(dāng)前線(xiàn)程,如果不是,扔到ObjectMonitor里的EntryList中,排隊(duì),并掛起線(xiàn)程,等待被喚醒。

image.png

4.4 wait為什么是Object下的方法?

執(zhí)行wait方法需要持有sync鎖。

sync鎖可以是任意對(duì)象。

同時(shí)執(zhí)行wait方法是在持有sync鎖的時(shí)候,釋放鎖資源。

其次wait方法需要去操作ObjectMonitor,而操作ObjectMonitor就必須要在持有鎖資源的前提的才能操作,將當(dāng)前線(xiàn)程扔到WaitSet等待池中。

同理,notify方法需要將WaitSet等待池中線(xiàn)程扔到EntryList,如果不擁有ObjectMonitor,怎么操作!

類(lèi)鎖就是基于類(lèi).class作為 ? ? ? ? ? 類(lèi)鎖

對(duì)象鎖,就是new 一個(gè)對(duì)象作為 ?對(duì)象鎖

設(shè)計(jì)模式(單例,工廠(chǎng),代理,消費(fèi)者生產(chǎn)者,策略,責(zé)任鏈,觀(guān)察者,模板,裝飾者),多線(xiàn)程,JVM,MySQL,Spring,SpringBoot,Redis,MQ


Java 并發(fā)編程面試題(1)的評(píng)論 (共 條)

使用qq登录你需要登录后才可以评论。
姚安县| 彭州市| 翁源县| 长子县| 治多县| 庆安县| 读书| 城市| 泰兴市| 阿拉善左旗| 芜湖市| 平乐县| 鄱阳县| 金坛市| 汤阴县| 密山市| 孟连| 北辰区| 中卫市| 孝义市| 斗六市| 密云县| 色达县| 水城县| 苍溪县| 神木县| 屯门区| 石河子市| 临西县| 内江市| 焉耆| 远安县| 馆陶县| 枣阳市| 和田市| 泾阳县| 潜江市| 武山县| 兴业县| 酉阳| 鹤峰县|