關(guān)注我們,設(shè)為星標(biāo),每天7:30不見不散,架構(gòu)路上與您共享 回復(fù)"架構(gòu)師"獲取資源
垃圾回收機(jī)制算法
一個(gè)對象怎么判斷是垃圾被回收
引用計(jì)數(shù)法:是通過判斷對象的引用數(shù)量來決定對象是否可以被回收,很難處理循 環(huán)引用,相互引用的兩個(gè)對象則無法釋放。
可達(dá)性分析:這個(gè)算法的基本思想就是通過一系列的稱為 “GC Roots” 的對象作 為起點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,節(jié)點(diǎn)所走過的路徑稱為引用鏈當(dāng)一個(gè)對象到 GC Roots 沒有任何引用鏈相連的話,則證明此對象是不可用的。
JVM 架構(gòu),回收機(jī)制
方法區(qū):存儲(chǔ)已被虛擬機(jī)加載的類元數(shù)據(jù)信息(元空間)
堆:存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存
虛擬機(jī)棧:虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會(huì) 同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、 方法出口等信息
程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器
本地方法棧:本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。
volatile 關(guān)鍵字
Volatile是Java虛擬機(jī)提供的輕量級的同步機(jī)制(三大特性)
保證可見性(及時(shí)通知):變量被volatile修飾之后,當(dāng)該變量被修改之后使用到該變量的地方都會(huì)被感知到
不保證原子性:原子性是指不可分割,完整性,也就是說某個(gè)線程正在做某個(gè)具體業(yè)務(wù)時(shí),中間不可以被加塞或者被分割,需要具體完成,要么同時(shí)成功,要么同時(shí)失敗。
禁止指令重排:計(jì)算機(jī)在執(zhí)行程序時(shí),為了提高性能,編譯器和處理器常常會(huì)對指令重排。但是處理器在進(jìn)行重排時(shí)候,必須考慮到指令之間的數(shù)據(jù)依賴性。
說一下synchronized和lock的區(qū)別
1)synchronized屬于JVM層面,屬于java的關(guān)鍵字
monitorenter(底層是通過monitor對象來完成,其實(shí)wait/notify等方法也依賴于monitor對象 只能在同步塊或者方法中才能調(diào)用 wait/ notify等方法)
Lock是具體類(java.util.concurrent.locks.Lock)是api層面的鎖
2)使用方法:
synchronized:不需要用戶去手動(dòng)釋放鎖,當(dāng)synchronized代碼執(zhí)行后,系統(tǒng)會(huì)自動(dòng)讓線程釋放對鎖的占用
ReentrantLock:則需要用戶去手動(dòng)釋放鎖,若沒有主動(dòng)釋放鎖,就有可能出現(xiàn)死鎖的現(xiàn)象,需要lock() 和 unlock() 配置try catch語句來完成
3)等待是否中斷
synchronized:不可中斷,除非拋出異常或者正常運(yùn)行完成
ReentrantLock:可中斷,可以設(shè)置超時(shí)方法
設(shè)置超時(shí)方法,trylock(long timeout, TimeUnit unit)
lockInterrupible() 放代碼塊中,調(diào)用interrupt() 方法可以中斷
4)加鎖是否公平
synchronized:非公平鎖
ReentrantLock:默認(rèn)非公平鎖,構(gòu)造函數(shù)可以傳遞boolean值,true為公平鎖,false為非公平鎖
5)鎖綁定多個(gè)條件Condition
synchronized:沒有,要么隨機(jī),要么全部喚醒
ReentrantLock:用來實(shí)現(xiàn)分組喚醒需要喚醒的線程,可以精確喚醒,而不是像synchronized那樣,要么隨機(jī),要么全部喚醒
悲觀鎖和樂觀鎖
樂觀鎖:顧名思義,就是十分樂觀,它總是認(rèn)為不會(huì)出現(xiàn)問題,無論干什么都不去 上鎖,如果出現(xiàn)了問題,再次更新值測試,這里使用了version字段。
也就是每次更新的時(shí)候同時(shí)維護(hù)一個(gè)version字段。
可以使用CAS(compare and swap)實(shí)現(xiàn),CAS是由CPU硬件實(shí)現(xiàn),所以執(zhí)行相當(dāng)快.CAS 有三個(gè)操作參數(shù):內(nèi)存地址,期望值,要修改的新值,當(dāng)期望值和內(nèi)存當(dāng)中的值進(jìn) 行比較不相等的時(shí)候,表示內(nèi)存中的值已經(jīng)被別線程改動(dòng)過,這時(shí)候失敗返回,當(dāng) 相等的時(shí)候,將內(nèi)存中的值改為新的值,并返回成功。
悲觀鎖:顧名思義,就是十分悲觀,它總是認(rèn)為什么時(shí)候都會(huì)出現(xiàn)問題,無論什么 操作都會(huì)上鎖,再次操作,synchronized就是一個(gè)典型的悲觀鎖
線程池的創(chuàng)建
Executors工具類和ThreadPoolExecutor方式創(chuàng)建推薦使用ThreadPoolExecutor方式創(chuàng)建,其中有七個(gè)參數(shù)
corePoolSize:線程池中的常駐核心線程數(shù)
maximumPoolSize:線程池中能夠容納同時(shí) 執(zhí)行的最大線程數(shù),此值必須大于等于1
keepAliveTime:多余的空閑線程的存活時(shí)間 當(dāng)前池中線程數(shù)量超過corePoolSize時(shí),當(dāng)空閑時(shí)間達(dá)到keepAliveTime時(shí),多余線程會(huì)被銷毀直到 只剩下corePoolSize個(gè)線程為止
unit:keepAliveTime的單位
workQueue:任務(wù)隊(duì)列,被提交但尚未被執(zhí)行的任務(wù)
threadFactory:表示生成線程池中工作線程的線程工廠, 用于創(chuàng)建線程,一般默認(rèn)的即可
handler:拒絕策略,表示當(dāng)隊(duì)列滿了,并且工作線程大于 等于線程池的最大線程數(shù)(maximumPoolSize)時(shí),如何來拒絕 請求執(zhí)行的runnable的策略
cpu占用滿了如何排查
先用top命令,找到cpu占用最高的進(jìn)程 PID
再用ps -mp pid -o THREAD,tid,time
查詢進(jìn)程中,那個(gè)線程的cpu占用 率高記住TID
jstack 29099 >> xxx.log 打印出該進(jìn)程下線程日志
sz xxx.log 將日志文件下載到本地
寫一個(gè)死鎖
/**
* 資源類
*/
class Lock implements Runnable {
private String lockA;
private String lockB;
public Lock(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA) {
System.out.println(Thread.currentThread().getName() + "用了" + lockA + "想獲取" + lockB);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
System.out.println(Thread.currentThread().getName() + "用了" + lockB + "想獲取" + lockA);
}
}
}
}
public class DeadLockDemo01 {
/**
* 線程 操作 資源類
*/
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new Lock(lockA, lockB), "T1").start();
new Thread(new Lock(lockB, lockA), "T2").start();
}
}
線程數(shù)是怎么設(shè)置的
使用ThreadPoolExecutor 第一個(gè)參數(shù)就是核心線程數(shù)
說一下創(chuàng)建線程的方式,以及線程的狀態(tài)吧
傳統(tǒng)的是繼承thread類和實(shí)現(xiàn)runnable接口
java5以后又有實(shí)現(xiàn)callable接口和java的線程池獲得
線程狀態(tài)
①創(chuàng)建狀態(tài)
②就緒狀態(tài)
③運(yùn)行狀態(tài)
④阻塞狀態(tài)
⑤死亡狀態(tài)
線程池的運(yùn)行原理
在創(chuàng)建了線程池后,線程池中的線程數(shù)為零。
當(dāng)調(diào)用execute()方法添加一個(gè)請求任務(wù)時(shí),線程池會(huì)做出如下判斷:
如果正在運(yùn)行的線程數(shù)量小于corePoolSize,那么馬上創(chuàng)建線程運(yùn)行這個(gè)任務(wù);
如果正在運(yùn)行的線程數(shù)量大于或等于corePoolSize,那么將這個(gè)任務(wù)放入隊(duì)列;
如果這個(gè)時(shí)候隊(duì)列滿了且正在運(yùn)行的線程數(shù)量還小于maximumPoolSize,那么還是要?jiǎng)?chuàng)建非核心線程立刻運(yùn)行這個(gè)任務(wù);
如果隊(duì)列滿了且正在運(yùn)行的線程數(shù)量大于或等于maximumPoolSize,那么線程池會(huì)啟動(dòng)飽和拒絕策略來執(zhí)行。
當(dāng)一個(gè)線程完成任務(wù)時(shí),它會(huì)從隊(duì)列中取下一個(gè)任務(wù)來執(zhí)行。
當(dāng)一個(gè)線程無事可做超過一定的時(shí)間(keepAliveTime)時(shí),線程會(huì)判斷:
如果當(dāng)前運(yùn)行的線程數(shù)大于corePoolSize,那么這個(gè)線程就被停掉。
所以線程池的所有任務(wù)完成后,它最終會(huì)收縮到corePoolSize的大小。
介紹一下jvm
方法區(qū):存儲(chǔ)已被虛擬機(jī)加載的類元數(shù)據(jù)信息(元空間)
堆:存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存
虛擬機(jī)棧:虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會(huì) 同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法 出口等信息
程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器
本地方法棧:本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。
寫一個(gè)線程安全的單例模式()
// 懶漢式單例模式會(huì)有線程安全問題
public void SingleTonDemo{
// 私有化構(gòu)造器
private SingleTonDemo(){};
// 私有屬性
private static Volatile SingleTonDemo std = null;
// 提供公有方法
public SingleTonDemo getStd(){
If(std == null){
Synchronized(SingleTonDemo.class){
If(std == null){
Std = new SingleTonDeno();
}
}
}
return std;
}
}
談?wù)勀銓uc的理解
是Java5.0提供的一個(gè)java.util.concurrent包,在包中提供了一些并發(fā)編程中很常用的工具類。
創(chuàng)建線程有四種方式:
繼承Thread類
實(shí)現(xiàn)Runnable接口
實(shí)現(xiàn)Callable接口 + FutureTask類
線程池
allable接口與runnable接口的區(qū)別?
相同點(diǎn):
都是接口,都可以編寫多線程程序,都采用Thread.start()啟動(dòng)線程
不同點(diǎn):
具體方法不同:一個(gè)是run,一個(gè)是call
Runnable沒有返回值;Callable可以返回執(zhí)行結(jié)果,是個(gè)泛型
Callable接口的call()方法允許拋出異常;Runnable的run()方法異常只能在內(nèi)部消化,不能往上繼續(xù)拋它提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并檢索計(jì)算的結(jié)果。
synchronized和lock鎖的區(qū)別
Synchronized是java的一個(gè)關(guān)鍵字
Lock 屬于api層面
Synchronized可以自動(dòng)解鎖
Lock需要手動(dòng)解鎖
Synchronized中途不可以中斷
Lock可以中斷
Synchrozied屬于公平鎖
Lock既可以是公平鎖又可以是非公平鎖根據(jù)傳入的參數(shù)
喚醒機(jī)制:synchronized只能全部喚醒
Lock可以根據(jù)條件喚醒不同的線程
談?wù)勀銓olatile的理解
Volatile是一個(gè)輕量級的同步機(jī)制,它有三個(gè)屬性:
保證可見性
不保證原子性
禁止指令重排
說說類加載器類型和JVM內(nèi)存結(jié)構(gòu)
類加載器:啟動(dòng)類加載器(Bootstrap)C++、擴(kuò)展類加載器(Extension)Java、應(yīng)用程序類加載器(AppClassLoader)Java、用戶自定義加載器 Java.lang.ClassLoader的子類,用戶可以定制類的加載方式
雙親委派模型。簡單來說:如果一個(gè)類加載器收到了類加載的請求,它首先不會(huì)自 己去嘗試加載這個(gè)類, 而是把請求委托給父加載器去完成,依次向上。
棧:虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法出口等信息
堆:存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存
方法區(qū):存儲(chǔ)已被虛擬機(jī)加載的類元數(shù)據(jù)信息(元空間)
程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器
本地方法棧:本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。
執(zhí)行引擎
本地方法接口:執(zhí)行本地方法庫
thread.sleep()和wait()區(qū)別?還問了wait()鎖的問題?
所屬類不同:sleep屬于Thread類,wait屬于Object類
是否釋放鎖:sleep不釋放線程所擁有的監(jiān)視器資源,而wait會(huì)把監(jiān)視器資源釋放
用法不同:wait()方法通常用于線程間的交互和通信,sleep通常用于暫停執(zhí)行
用途不同:wait()方法被調(diào)用后,如果沒有設(shè)置等待時(shí)間,線程不會(huì)自動(dòng)蘇醒,需要?jiǎng)e的線程調(diào)用共享變量的notify()或notifyAll()方法。sleep()方法在等待時(shí)間到了之后,會(huì)自動(dòng)蘇醒
sleep()睡眠時(shí),保持對象鎖,仍然占有該鎖;其他線程無法訪問
而wait()睡眠時(shí),釋放對象鎖。其他線程可以訪問
valitile關(guān)鍵字
Java多線程中的輕量的同步機(jī)制有三個(gè)屬性
JMM是Java內(nèi)存模型,也就是Java Memory Model,簡稱JMM,本身是一種抽象的概念,實(shí)際上并不存在,它描述的是一組規(guī)則或規(guī)范,通過這組規(guī)范定義了程序中各個(gè)變量(包括實(shí)例字段,靜態(tài)字段和構(gòu)成數(shù)組對象的元素)的訪問方式
JMM關(guān)于同步的規(guī)定:
線程解鎖前,必須把共享變量的值刷新回主內(nèi)存
線程解鎖前,必須讀取主內(nèi)存的最新值,到自己的工作內(nèi)存
加鎖和解鎖是同一把鎖
線程的創(chuàng)建中,runnable和callable區(qū)別?
相同點(diǎn):都是接口,都可以編寫多線程程序,都采用Thread.start()啟動(dòng)線程
不同點(diǎn):
具體方法不同:一個(gè)是run,一個(gè)是call
Runnable沒有返回值;Callable可以返回執(zhí)行結(jié)果,是個(gè)泛型
Callable接口的call()方法允許拋出異常;Runnable的run()方法異常只能在內(nèi)部消化,不能往 上繼續(xù)拋
它提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并檢索計(jì)算的結(jié)果。
分布式鎖如何實(shí)現(xiàn)?
分布式鎖的三種實(shí)現(xiàn)方式:mysql redis(性能最高) zk(安全性最高)
特征:
1.獨(dú)占排他
2.可重入性(可選)
3.防止死鎖的發(fā)生
4.防誤刪
5.自動(dòng)續(xù)期
6.原子性:加鎖 解鎖
7.redlock算法
實(shí)現(xiàn):
setnx實(shí)現(xiàn)獨(dú)占排他
防止死鎖發(fā)生 過期時(shí)間 set key value ex 3000 nx
lua腳本 或者 set key value ex 3000 nx 保證原子性
為了做到防誤刪 給鎖添加過期時(shí)間
監(jiān)控子線程做到自動(dòng)續(xù)期
總結(jié):
加鎖:set key value ex 3000 nx 實(shí)現(xiàn)獨(dú)占排他 設(shè)置過期時(shí)間,防止死鎖發(fā)生,并保證原子性
解鎖:lua腳本解鎖,防止誤刪并保證原子性
監(jiān)控子線程做到自動(dòng)續(xù)期
重試:獲取鎖失敗的線程,重試
可重入鎖:使用了lua腳本,hash數(shù)據(jù)結(jié)構(gòu),每重入一次value+1,每釋放一次value-1,直到value=0時(shí),刪除鎖
redisson分布鎖框架:
ReentrantLock可重入鎖
FireLock公平鎖
RedLock紅鎖:大部分實(shí)例獲取到鎖
ReadWriteLock讀寫鎖
CountDownLatch閉鎖
Semaphore分布式信號量
怎么做到自動(dòng)續(xù)期:看門狗子線程
怎么防止集群情況下鎖失效:RedLock
AOP封裝緩存和分布式鎖:
注解 + 環(huán)繞通知
IOC原理:反轉(zhuǎn)控制 大工廠 + 配置文件 + 反射
4種初始化方式:無參構(gòu)造器 靜態(tài)工廠 實(shí)例化工程 factoryBean
DI依賴注入:依賴于IOC
2種方式:setter注入 構(gòu)造方法
AOP原理:動(dòng)態(tài)代理(JDK代理 CGLIB代理)
@Aspect @Before @Around
切入點(diǎn)表達(dá)式:execution(* com.atguigu.gmall.pms.service.*.*(..)) annotation(注解的全路徑)
JoinPoint
joinPoint.getArgs()
joinPoint.getTarget().getClass()
(MethodSignature)joinPoint.getSignature
線程池創(chuàng)建方式,和前兩個(gè)參數(shù)
線程池創(chuàng)建的兩種方式:Executors工具類和ThreadPoolExecutor類
核心線程數(shù)
存活時(shí)間
時(shí)間單位
最大線程數(shù)
阻塞隊(duì)列
線程工廠
拒絕策略
mq怎么保證消息不丟失
線程工具類介紹一下
Executors工具類線程池創(chuàng)建的方法有:固定數(shù)的,單一的,可變的。
線程池不允許使用Executors去創(chuàng)建,而是通過ThreadToolExecutors的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)
Executors返回的線程池對象弊端如下:
FixedThreadPool和SingleThreadPool:
運(yùn)行的請求隊(duì)列長度為:Integer.MAX_VALUE,可能會(huì)堆積大量的請求,從而導(dǎo)致OOM
CacheThreadPool和ScheduledThreadPool
運(yùn)行的請求隊(duì)列長度為:Integer.MAX_VALUE,可能會(huì)堆積大量的請求,從而導(dǎo)致OO
線程的狀態(tài)
創(chuàng)建 就緒 運(yùn)行 阻塞 死亡
死鎖是怎么發(fā)生的,怎么解決
死鎖的四個(gè)必要條件
解決方法:把互斥的共享資源封裝成可同時(shí)訪問
解決方法:進(jìn)程請求資源時(shí),要求它不占有任何其它資源,也就是它必須一次性申請到所有的資源,這種方式會(huì)導(dǎo)致資源效率低。
解決方法:如果進(jìn)程不能立即分配資源,要求它不占有任何其他資源,也就是只能夠同時(shí)獲得所有需要資源時(shí),才執(zhí)行分配操作
解決方法:對資源進(jìn)行排序,要求進(jìn)程按順序請求資源。
如何保證線程的同步?
使用synchronized ReentrandLock保證線程同步
Java鎖的基本狀態(tài)
無鎖 偏向鎖 輕量級鎖 重量級鎖
一個(gè)對象加鎖的狀態(tài)?
鎖是存在哪里的呢?
鎖存在Java的對象頭中的Mark Work。Mark Work默認(rèn)不僅存放著鎖標(biāo)志位,還存放對象hashCode等信息。運(yùn)行時(shí),會(huì)根據(jù)鎖的狀態(tài),修改Mark Work的存儲(chǔ)內(nèi)容。如果對象是數(shù)組類型,則虛擬機(jī)用3個(gè)字寬存儲(chǔ)對象頭,如果對象是非數(shù)組類型,則用2字寬存儲(chǔ)對象頭。在32位虛擬機(jī)中,一字寬等于四字節(jié),即32bit。
字寬(Word): 內(nèi)存大小的單位概念, 對于 32 位處理器 1 Word = 4 Bytes, 64 位處理器 1 Word = 8 Bytes
每一個(gè) Java 對象都至少占用 2 個(gè)字寬的內(nèi)存(數(shù)組類型占用3個(gè)字寬)。
第一個(gè)字寬也被稱為對象頭Mark Word。對象頭包含了多種不同的信息, 其中就包含對象鎖相關(guān)的信息。
第二個(gè)字寬是指向定義該對象類信息(class metadata)的指針
四種狀態(tài)
鎖有四種狀態(tài):無鎖狀態(tài)、偏向鎖、輕量級鎖、重量級鎖
隨著鎖的競爭,鎖的狀態(tài)會(huì)從偏向鎖到輕量級鎖,再到重量級鎖。而且鎖的狀態(tài)只有升級,沒有降級。也就是只有偏向鎖->輕量級鎖->重量級鎖,沒有重量級鎖->輕量級鎖->偏向鎖。
鎖狀態(tài)的改變是根據(jù)競爭激烈程度進(jìn)行的,在幾乎無競爭的條件下,會(huì)使用偏向鎖,在輕度競爭的條件下,會(huì)由偏向鎖升級為輕量級鎖, 在重度競爭的情況下,會(huì)升級到重量級鎖。
你為什么說synchronized是重量級鎖?
操作系統(tǒng)維護(hù)鎖的狀態(tài)使當(dāng)前線程掛起外,只要是synchronized,一有競爭也會(huì)引起阻塞,阻塞和喚醒操作又涉及到了上下文操作,大量消耗CPU,降低性能。
重量級鎖是需要依靠操作系統(tǒng)來實(shí)現(xiàn)互斥鎖的,這導(dǎo)致大量上下文切換,消耗大量CPU,影響性能。
公平鎖和非公平鎖的區(qū)別?
是指多個(gè)線程按照申請鎖的順序來獲取鎖,類似于排隊(duì)買飯,先來后到,先來先服務(wù),就是公平的,也就是隊(duì)列
是指多個(gè)線程獲取鎖的順序,并不是按照申請鎖的順序,有可能申請的線程比先申請的線程優(yōu)先獲取鎖,在高并發(fā)環(huán)境下,有可能造成優(yōu)先級翻轉(zhuǎn),或者饑餓的線程(也就是某個(gè)線程一直得不到鎖)
并發(fā)包中ReentrantLock的創(chuàng)建可以指定析構(gòu)函數(shù)的boolean類型來得到公平鎖或者非公平鎖,默認(rèn)是非公平鎖
/**
* 創(chuàng)建一個(gè)可重入鎖,true 表示公平鎖,false 表示非公平鎖。默認(rèn)非公平鎖
*/
Lock lock = new ReentrantLock(true);
公平鎖:就是很公平,在并發(fā)環(huán)境中,每個(gè)線程在獲取鎖時(shí)會(huì)先查看此鎖維護(hù)的等待隊(duì)列,如果為空,或者當(dāng)前線程是等待隊(duì)列中的第一個(gè),就占用鎖,否者就會(huì)加入到等待隊(duì)列中,以后安裝FIFO的規(guī)則從隊(duì)列中取到自己
非公平鎖:非公平鎖比較粗魯,上來就直接嘗試占有鎖,如果嘗試失敗,就再采用類似公平鎖那種方式。題外話
Java ReenttrantLock通過構(gòu)造函數(shù)指定該鎖是否公平,默認(rèn)是非公平鎖,因?yàn)榉枪芥i的優(yōu)點(diǎn)在于吞吐量比公平鎖大,對于synchronized而言,也是一種非公平鎖
JUC下的工具類有哪些
CountDownLatch
概念
讓一些線程阻塞直到另一些線程完成一系列操作才被喚醒
CountDownLatch主要有兩個(gè)方法,當(dāng)一個(gè)或多個(gè)線程調(diào)用await方法時(shí),調(diào)用線程就會(huì)被阻塞。其它線程調(diào)用CountDown方法會(huì)將計(jì)數(shù)器減1(調(diào)用CountDown方法的線程不會(huì)被阻塞),當(dāng)計(jì)數(shù)器的值變成零時(shí),因調(diào)用await方法被阻塞的線程會(huì)被喚醒,繼續(xù)執(zhí)行
概念
和CountDownLatch相反,需要集齊七顆龍珠,召喚神龍。也就是做加法,開始是0,加到某個(gè)值的時(shí)候就執(zhí)行
CyclicBarrier的字面意思就是可循環(huán)(cyclic)使用的屏障(Barrier)。它要求做的事情是,讓一組線程到達(dá)一個(gè)屏障(也可以叫同步點(diǎn))時(shí)被阻塞,直到最后一個(gè)線程到達(dá)屏障時(shí),屏障才會(huì)開門,所有被屏障攔截的線程才會(huì)繼續(xù)干活,線程進(jìn)入屏障通過CyclicBarrier的await方法
概念
信號量主要用于兩個(gè)目的
一個(gè)是用于共享資源的互斥使用
另一個(gè)用于并發(fā)線程數(shù)的控制
git的合并沖突
沖突是指當(dāng)你在提交或者更新代碼時(shí)被合并的文件與當(dāng)前文件不一致
常見沖突的生產(chǎn)場景如下
更新代碼
提交代碼
多個(gè)分支代碼合并到一個(gè)分支時(shí)
多個(gè)分支向同一個(gè)遠(yuǎn)端分支推送代碼時(shí)
git的合并中產(chǎn)生沖突的具體情況:
<1>兩個(gè)開發(fā)者(分支中)修改了同一個(gè)文件(不管什么地方)
<2>兩個(gè)開發(fā)者(分支中)修改了同一個(gè)文件的名稱
注意:兩個(gè)分支中分別修改了不同文件中的部分,不會(huì)產(chǎn)生沖突,可以直接將兩部分合并。
總結(jié):上面各種情況的本質(zhì)都是,當(dāng)前文件與合并文件不一致,因此不論哪種情況其解決沖突的方法是一樣的。
最后:代碼沖突之后,和為貴!!!
分布式鎖用的是什么?
MySQL redis zk三種方式
線程中sleep()、 wait()、 join()、 yield()的區(qū)別
sleep()方法是讓當(dāng)前運(yùn)行這一句的代碼休眠指定的一段時(shí)間,在休眠時(shí)間里,線程不會(huì)獲取CPU的執(zhí)行權(quán),如果當(dāng)前線程持有了對象鎖,是不會(huì)釋放對象鎖的,過了休眠時(shí)間線程自動(dòng)轉(zhuǎn)為可運(yùn)行狀態(tài)。
wait()方法是讓當(dāng)前線程等待一段時(shí)間,這段時(shí)間里,線程將一直處于阻塞狀態(tài),直到被notify()或者notifyAll()方法喚醒,如果線程持有對象鎖,會(huì)釋放對象鎖,wait()和notify()方法都是object對象的方法,而不是線程獨(dú)有的方法,另外,wait()和notify()方法運(yùn)行時(shí)必須持有鎖(即代碼要是同步的),否則會(huì)報(bào)錯(cuò),wait()會(huì)釋放鎖也是因?yàn)閚otify()要得到鎖,但是notify()方法并不會(huì)釋放鎖,所以一般把notify()放在代碼最后。
yield()方法是線程完成自己的任務(wù)時(shí),自己回到可運(yùn)行狀態(tài),參與爭奪CPU執(zhí)行權(quán),且線程不會(huì)釋放對象鎖。
在一個(gè)線程A中運(yùn)行了線程B的join()方法,則線程A必須等到線程B執(zhí)行完后才能開始執(zhí)行,可以用于保證線程的執(zhí)行先后順序。
interrupt()方法是為線程設(shè)立一個(gè)中斷標(biāo)志,相當(dāng)于一個(gè)通知,但是線程是否中斷,是有線程自己決定的,也就是說線程調(diào)用interrpt()方法不代表著線程一定會(huì)中斷,如果線程中運(yùn)行了sleep()方法,并拋出InterruptedException,那么當(dāng)前線程的中斷狀態(tài)會(huì)被重置。
isInterrupted()方法是判斷調(diào)用該方法的線程是否處于中斷狀態(tài),但是不會(huì)重置線程狀態(tài)。
文章來源:https://blog.csdn.net/Ding9610/article/details/108432903
到此文章就結(jié)束了。如果今天的文章對你在進(jìn)階架構(gòu)師的路上有新的啟發(fā)和進(jìn)步,歡迎轉(zhuǎn)發(fā)給更多人。歡迎加入架構(gòu)師社區(qū)技術(shù)交流群,眾多大咖帶你進(jìn)階架構(gòu)師,在后臺回復(fù)“加群”即可入群。
這些年小編給你分享過的干貨
1.第七期打卡送書5本(5月1日-6月1日)
2.ERP系統(tǒng),自帶進(jìn)銷存+財(cái)務(wù)+生產(chǎn)功能,拿來即用
3.帶工作流的SpringBoot后臺管理項(xiàng)目快速開發(fā)解決方案
4.最好的OA系統(tǒng),拿來即用,非常方便
5.SpringBoot+Vue完整的外賣系統(tǒng),手機(jī)端和后臺管理,附源碼!
轉(zhuǎn)發(fā)在看就是最大的支持??