多線程基礎(chǔ)總結(jié)
一、線程中斷
interrupt
方法用來(lái)請(qǐng)求終止線程裆操。
1. interrupt
置位中斷標(biāo)志位
當(dāng)對(duì)一個(gè)線程調(diào)用interrupt
方法時(shí),線程的中斷標(biāo)志位被置位炉媒,表示請(qǐng)求終止線程踪区。
// 線程將中斷作為終止程序的請(qǐng)求
Runnable r1 = () -> {
try {
Thread.sleep(1000); // 阻塞
// 正常情況下檢測(cè)中斷標(biāo)志位
while (!Thread.currentThread().isInterrupted()) {
// has work to do
}
} catch (InterruptedException e) {
// 線程在阻塞的時(shí)候被中斷
} finally {
// 清除資源
}
// 退出程序
};
2. 如果線程被阻塞,調(diào)用interrupt
方法橱野,阻塞調(diào)用會(huì)被InterruptedException
異常中斷朽缴。
此時(shí),應(yīng)捕獲InterruptedException
異常水援。
// 阻塞的時(shí)候被中斷密强,會(huì)清除中斷標(biāo)識(shí)位,并拋出中斷異常
Runnable r2 = () -> {
try {
while (true) {
// has work to do
Thread.sleep(1000); // 睡眠的時(shí)候產(chǎn)生中斷
}
} catch (InterruptedException e) {
// 線程在阻塞的時(shí)候被中斷
} finally {
// 清除資源
}
// 退出程序
};
3.兩個(gè)類似的方法interrupted
與isInterrupted
-
interrupted
方法為靜態(tài)方法蜗元,檢測(cè)線程是否被中斷或渤,并清除中斷標(biāo)志位。 -
isInterrupted
方法為實(shí)例方法奕扣,用來(lái)檢測(cè)線程的中斷狀態(tài)薪鹦,但不清除中斷標(biāo)志位。
4.使用不當(dāng)及糾正
void mySubTask() {
...
try {sleep(delay)}
catch (InterruptedException e) {} // 被忽略
}
上述代碼中的中斷異常不應(yīng)被忽略,有以下兩種選擇:
-
在catch中調(diào)用Thread.currentThread().interrupt()來(lái)設(shè)置中斷狀態(tài)池磁。調(diào)用者可以來(lái)檢測(cè)奔害。
void mySubTask() { ... try {sleep(delay)} catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 被忽略 }
-
拋出
InterruptedException
異常,不try
捕獲異常地熄。上層可以捕獲該異常华临。void mySubTask() throws InterruptedException{ ... sleep(delay) ... }
二、線程狀態(tài)
線程狀態(tài)轉(zhuǎn)換圖
Blocked
和Waiting
的區(qū)別:
-
Blocked
:只有synchronized
會(huì)導(dǎo)致線程進(jìn)入Blocked
狀態(tài)端考,即一個(gè)線程試圖獲取一個(gè)對(duì)象的鎖雅潭,而該鎖被其他線程持有時(shí),該線程會(huì)阻塞却特。當(dāng)所有其他線程釋放該鎖扶供,并且線程調(diào)度器允許本線程持有鎖時(shí),該線程變?yōu)榉亲枞麪顟B(tài)裂明。 -
Waiting
:Object.wait()
導(dǎo)致線程進(jìn)入Waiting
狀態(tài)椿浓,Waiting
線程被其他線程調(diào)用Object.notify()
喚醒之后,重新獲取對(duì)象上的鎖的時(shí)候(但沒(méi)獲取到)也會(huì)進(jìn)入Blocked
狀態(tài)漾岳。被喚醒的線程需要重新獲取到對(duì)象的鎖才能恢復(fù)執(zhí)行轰绵。
三、鎖對(duì)象
1.可重入鎖ReentrantLock
模板代碼:?
Lock myLock = new ReentrantLock();
myLock.lock(); // 互斥尼荆、可重入
try {
// 臨界區(qū)
} finally {
myLock.unlokc();
}
2.條件Condition
**`Lock`下更加細(xì)粒度的并發(fā)控制.**
`Condition`用來(lái)控制左腔、管理那些已經(jīng)獲得了一個(gè)鎖,但是卻因?yàn)椴粷M足條件而不能做有用工作的線程捅儒。一個(gè)鎖對(duì)象可以有一個(gè)或多個(gè)條件對(duì)象液样。
private Lock bankLock = new ReentrantLock();;
private Condition sufficientFunds = bankLock.newCondition(); // 足夠的資金
// sufficientFunds.await(); ---> sufficientFunds.signalAll();
public void transfer(int from, int to, int amount) {
bankLock.lock();
try {
while(account[from] < amount) {
sufficientFunds.await()巧还; // 金額不足鞭莽,阻塞
}
// transfer funds
sufficientFunds.signalAll(); // signalAll()
} finally {
bankLock.unlock();
}
}
四、synchronized
關(guān)鍵字
Java
中的每一個(gè)對(duì)象都有一個(gè)內(nèi)部鎖麸祷。如果一個(gè)方法用synchronized
聲明澎怒,則對(duì)象的鎖將保護(hù)整個(gè)方法。
public synchronized void method() {
// method body
}
// 等價(jià)于
public void method() {
this.intrinsicLock.lock();
try {
// method body
} finally {
this.intrinsicLock.unlock();
}
}
內(nèi)部對(duì)象鎖只有一個(gè)條件阶牍,調(diào)用wait()
添加一個(gè)線程到條件的等待集中喷面,notifyAll/notify()
方法解除等待線程的阻塞狀態(tài)。
intrinsicCondition.await() ---- wait()
intrinsicCondition.signalAll() ---- notifyAll()