<center>第二章</center>
線程安全知識
- 線程安全的代碼其核心在于要對狀態(tài)訪問進(jìn)行管理,比如 共享的、可變的狀態(tài)。
- 正確的編程方式是首先使代碼正確運(yùn)行,然后再提高代碼的速度。
- 什么是線程安全性
- 當(dāng)多個(gè)線程訪問某個(gè)類時(shí),這個(gè)類始終都能編寫出正確的行為。
- 無狀態(tài)對象一定是線程安全的,比如局部變量。
public class StatelessFactorizer implements Servlet{
public void service(ServletRequest
rep,ServletResponse resp){ BigInteger i=extractFromRequest(rep);
BigInteger[] factors=factor(i);
encodeIntoResponse(rep,resp);
} }
<a><center>以上是否是線程安全的?</center></a>
-
原子性
所謂原子操作是指不會被線程調(diào)度機(jī)制打斷的操作;這種操作一旦開始,就一直運(yùn)行到結(jié)束,中間不會有任何上下文切換到另一個(gè)線程(比如數(shù)據(jù)庫事物)public class StatelessFactorizer implements Servlet{ private long conut=0; public void service(ServletRequest rep,ServletResponse resp){ BigInteger i=extractFromRequest(rep); BigInteger[] factors=factor(i); ++count; encodeIntoResponse(rep,resp); } }
<a><center>** 在多線程里面以上會出現(xiàn)什么問題**</center></a>
+ 由于不恰當(dāng)執(zhí)行時(shí)序而出現(xiàn)不正確的結(jié)果稱為競態(tài)條件。
1. 基于一種可能失效的觀察結(jié)果來做出判斷或者執(zhí)行某個(gè)計(jì)算,這種競態(tài)條件稱為先檢查后執(zhí)行。比如(延遲初始化、懶加載、懶加載代理)
<code>
public class Singleton {
private B instance=null;
public B getInstance() {
if (instance == null) {
instance = new B();
}
return single;
}
</code>
-
復(fù)合操作(其實(shí)就是多個(gè)原子操作)
比如修復(fù)上面代碼出現(xiàn)的問題,將++count 變?yōu)橐粋€(gè)原子操作(暫時(shí)使用線程安全類來解決)。public class StatelessFactorizer implements Servlet{ private AtomicLong conut=new AtomicLong(); public void service(ServletRequest rep,ServletResponse resp){ BigInteger i=extractFromRequest(rep); BigInteger[] factors=factor(i); count.incrementAndGet(); encodeIntoResponse(rep,resp); } } -
加鎖機(jī)制
-
內(nèi)置鎖(互斥鎖) 每一個(gè)對象都可以做實(shí)現(xiàn)同步的鎖,并且是可重入的。
public class Widget { public synchronized void doSomething() { } } public class LoggingWidget extends Widget { public synchronized void doSomething() { System.out.println(toString() + ": callingdoSomething"); super.doSomething(); } }
-
-
鎖保護(hù)狀態(tài)
- 對于可能被多個(gè)線程同時(shí)訪問的可變狀態(tài)變量,在訪問它時(shí)都需要持有同一個(gè)鎖,我們稱狀態(tài)變量是由這個(gè)鎖保護(hù)的。并且建議每個(gè)可變的變量都應(yīng)該由一個(gè)鎖來保護(hù)。