同步
多個線程同時修改一個數(shù)據(jù)時(也叫并發(fā)操作),容易導(dǎo)致同步問題(同時修改),產(chǎn)生臟數(shù)據(jù)
解決方法
在多個線程同時修改的數(shù)據(jù)上加鎖,當(dāng)一個線程修改時,另外的線程排隊(duì)等待,直到釋放鎖后其它線程才能占用,避免同時修改問題
MyStack實(shí)例代碼
死鎖
- 線程1占用A,接著請求占用B
- 線程2占用B,接著請求占用A
- 就這樣,兩個線程占用各自的,請求對方的,就形成死鎖

來自 how2j.cn
解決方法
- synchronized必須通過謹(jǐn)慎和良好的設(shè)計(jì),才能減少死鎖的發(fā)生。
- Lock可以選擇性的獲取鎖,trylock()會在指定時間范圍內(nèi)試圖占用,沒有占用成功會繼續(xù)往下走
// Lock 核心代碼
boolean locked = lock.tryLock(1,TimeUnit.SECONDS);
if(locked){
// 申請占用成功操作
}else{
// 沒有占用成功操作
}
交互
所謂交互,就是線程之間的交互通知
- syschronized 交互:wait(), notify(), notifyAll()
- Lock 交互:await(), signal(), signalAll()
生產(chǎn)者消費(fèi)者問題
生產(chǎn)者消費(fèi)者問題是一個非常典型性的線程交互的問題。它們公有一個緩沖區(qū),該問題的關(guān)鍵就是要保證生產(chǎn)者不會在緩沖區(qū)滿時加入數(shù)據(jù),消費(fèi)者也不會在緩沖區(qū)中空時消耗數(shù)據(jù)。
實(shí)現(xiàn)方法
- 使用棧來存放數(shù)據(jù)
- 把棧改造為支持線程安全
- 把棧的邊界操作進(jìn)行處理,當(dāng)棧里的數(shù)據(jù)是0的時候,訪問pull的線程就會等待。 當(dāng)棧里的數(shù)據(jù)時200的時候,訪問push的線程就會等待
- 提供一個生產(chǎn)者(Producer)線程類,生產(chǎn)隨機(jī)大寫字符壓入到堆棧
- 提供一個消費(fèi)者(Consumer)線程類,從堆棧中彈出字符并打印到控制臺
- 提供一個測試類,使兩個生產(chǎn)者和三個消費(fèi)者線程同時運(yùn)行
代碼
線程池
使用原因
每個線程的啟動和結(jié)束是比較消耗時間和占用內(nèi)存的(每個線程需要1MB內(nèi)存,線程開的越多,消耗的內(nèi)存越大,最后會死機(jī)),為了解決這個問題,所以引入線程池的概念
設(shè)計(jì)原理
線程池的思路與消費(fèi)者生產(chǎn)者模型很相似,主要兩函數(shù),任務(wù)添加 和 運(yùn)行任務(wù)
- 準(zhǔn)備一個任務(wù)容器
- 一次性啟動10個(根據(jù)需要)消費(fèi)線程
- 剛開始任務(wù)容器是空的,所以線程都是 wait()
- 直到外部環(huán)境往任務(wù)容器里放進(jìn)“任務(wù)”,就會有消費(fèi)線程被喚醒notify()

來自 how2j.cn
實(shí)例代碼
區(qū)別
生產(chǎn)者消費(fèi)者和線程池實(shí)現(xiàn)的區(qū)別在于:前一個是手動消費(fèi),后一個是自動消費(fèi)