版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、第六講面向安全的多線程設(shè)計吳際12022-7-1內(nèi)容摘要 理解并發(fā)機制 多線程程序常見的問題 線程安全問題 線程安全設(shè)計 作業(yè)22022-7-1并行與并發(fā)的概念差異 并行并行(parallel): 使用多個處理器資源來同時進行計算,從而提高完成任務(wù)的效率 例:google的Map Reduce就是使用多個分布的計算機來對搜索數(shù)據(jù)進行并行處理 例:使用多個線程來對給定數(shù)據(jù)進行按段排序 并發(fā)并發(fā)(concurrency): 多個執(zhí)行流(即線程)需要共享訪問某些公共資源(如數(shù)據(jù)) 例:云計算系統(tǒng)中,多個用戶(對應(yīng)為線程)同時要訪問云端資源,如數(shù)據(jù)文件 例:論壇系統(tǒng)中,多用戶同時發(fā)布帖子、回復(fù)帖子,帖
2、子成為共享資源 例:多個線程同時要訪問共享的數(shù)據(jù)CPUs/corestaskCPUs/coresresource2022-7-13程序為什么需要并發(fā)機制 和并行機制不同,引入并發(fā)的目標(biāo)并不總是獲得更快的計算效率 即便是單CPU、單核的平臺也需要并發(fā)機制 并發(fā)機制可以 提高程序的響應(yīng)效率 例:可視化界面程序通過線程并發(fā)提高GUI界面的響應(yīng)效率,從而獲得更好的可用性,后臺線程進行數(shù)據(jù)或任務(wù)計算 例:網(wǎng)絡(luò)通訊程序通過線程并發(fā)提高程序?qū)W(wǎng)絡(luò)請求的響應(yīng)效率 提高處理器的利用率,屏蔽I/O的延遲 如果一個線程在進行I/O慢速處理時,其他線程可以獲得處理器資源,提高整體利用率 有效隔離故障 一個線程執(zhí)行過程
3、中出現(xiàn)了故障,不會影響其他線程的執(zhí)行 網(wǎng)絡(luò)多用戶訪問情景2022-7-14線程執(zhí)行時序不確定性 使用線程并發(fā)機制會帶來好處,同時也會帶來潛在問題,即時序不確定性。如果兩個線程同時執(zhí)行一個方法: 哪個線程先執(zhí)行該方法是不確定的 一個線程執(zhí)行了多少指令后,另一個線程得到執(zhí)行也是不確定的 / Thread 1 / Thread 2 public void foo() public void foo() . statement1; statement1; . statement2; . . statement2; statement3; . statement3; Time2022-7-15線程執(zhí)行時
4、序不確定性public class Producer extends Thread private Tray tray; private int id; public Producer(Tray t, int id) tray = t; this.id = id; public void run() for (int i = 0; i 10; i+) for(int j =0; j 10; j+ ) tray.put(i, j); System.out.println(Producer # + this.id + put: (+i +,+j + ).); try sleep(int)(Math
5、.random() * 100); catch (InterruptedException e) ; 6public class ProducerConsumerTest public static void main(String args) Tray t = new Tray(); Producer p1 = new Producer(t, 1); Consumer c1 = new Consumer(t, 1); p1.start(); c1.start(); 2022-7-1線程執(zhí)行時序不確定性public class Consumer extends Thread private T
6、ray tray; private int id; public Consumer(Tray t, int id) tray = t; this.id = id; public void run() int value = 0; for (int i = 0; i 10; i+) value = tray.get(); System.out.println(Consumer # + this.id + got: + value); 7Consumer #1 got: 0Producer #1 put: (0,0).Consumer #1 got: 1Producer #1 put: (0,1)
7、.Producer #1 put: (0,2).Consumer #1 got: 2Consumer #1 got: 3Producer #1 put: (0,3).Consumer #1 got: 4Producer #1 put: (0,4).Producer #1 put: (0,5).Consumer #1 got: 5Producer #1 put: (0,6).Consumer #1 got: 6Consumer #1 got: 7Producer #1 put: (0,7).Consumer #1 got: 8Producer #1 put: (0,8).Producer #1
8、put: (0,9).Consumer #1 got: 9Producer #1 put: (1,0).2022-7-1線程執(zhí)行時序不確定性public class Tray private int x,y; private boolean available = false; public synchronized int get() while (available = false) try wait(); catch (InterruptedException e) available = false; / 此時available為真,確保所有其他消費者等待 notifyAll(); r
9、eturn x+y; public synchronized void put(int a, int b) while (available = true) try wait(); catch (InterruptedException e) x= a; y = b; available = true; / 喚醒等待隊列中的其他消費者或生產(chǎn)者 notifyAll(); 82022-7-1線程安全對象 Thread-safe class是關(guān)于對象如何被多個線程安全訪問,與對象的具體行為無關(guān)。 一個線程安全的類,在多個線程并發(fā)訪問該類的共享對象時,這個類行為的正確性不會受到線程調(diào)度、執(zhí)行時間等因素
10、影響,也不需要訪問該共享對象的線程在調(diào)用時額外進行同步控制。 共享對象才會出現(xiàn)線程安全問題 線程的調(diào)度和執(zhí)行時間具有不確定性 類行為的正確性指什么? 不可變對象是否存在線程安全問題?92022-7-1線程不安全的幾個實例 無狀態(tài)類與有狀態(tài)類在安全上的差異10public class CountingFactorizer implements Servlet private long count = 0; public long getCount() return count; public void service(ServletRequest req, ServletResponse res
11、p) BigInteger i = extractFromRequest(req); BigInteger factors = factor(i); +count; encodeIntoResponse(resp, factors); 無狀態(tài)對象的任何計算都只能使用局部變量,其引用只能在棧上,不會產(chǎn)生共享。有狀態(tài)對象的read-modify-write計算會導(dǎo)致出現(xiàn)不安全問題。Read x: =xUpdate x: x+1 Write to x: x=.2022-7-1線程不安全的幾個實例11x.f(y)Thread 1x.f(y)Thread 2xyx是無狀態(tài)共享對象y是有狀態(tài)共享對象x.f
12、(y)會改變y的狀態(tài)x是否線程安全?y是否線程安全?2022-7-1線程不安全的幾個實例 競爭條件(race conditions) 當(dāng)一個計算的正確性依賴于多個線程之間的相對執(zhí)行次序時,這幾個線程就出現(xiàn)了競爭條件。最常出現(xiàn)競爭條件的計算模式是 check-then-act, 可能會導(dǎo)致某個線程使用了過時的值進行檢查,從而做出錯誤的動作。 check-then-act: If (b_exp(x) do something with x update x 12public class LazyInitRace private ExpensiveObject instance = null; pu
13、blic ExpensiveObject getInstance() if (instance = null) instance = new ExpensiveObject(); return instance; 2022-7-1線程不安全的幾個實例 Read-modify-write和check-then-act是基本的計算模式,大量使用。 計算需要使用變量的當(dāng)前值 計算會改變變量的當(dāng)前值 這兩種計算模式出現(xiàn)線程安全隱患的主要原因是計算過程需要多步完成,無法保證計算的原子性 原子性:計算時不會被中途中斷 為了滿足計算的原子性,需要使用互斥機制 Java提供了一系列保證計算原子性的數(shù)據(jù)類型 鎖
14、(lock)132022-7-1線程不安全的幾個實例 如果read-modify-write和check-then-act計算只涉及單一變量,就可以通過java.util.concurrent.atomic包中提供的Atomic*類型來確保計算的原子性。14import java.util.concurrent.atomic;public class CountingFactorizer implements Servlet private final AtomicLong count = new AtomicLong(0); public long getCount() return cou
15、nt.get(); public void service(ServletRequest req, ServletResponse resp) BigInteger i = extractFromRequest(req); BigInteger factors = factor(i); count.incrementAndGet(); encodeIntoResponse(resp, factors); 2022-7-1線程不安全的幾個實例 如果一個類里有多個需要確保計算原子性的屬性怎么辦?15import java.util.concurrent.atomic;public class Un
16、safeCachingFactorizer implements Servlet private final AtomicReference lastNumber = new AtomicReference(); private final AtomicReference lastFactors = new AtomicReference(); public void service(ServletRequest req, ServletResponse resp) BigInteger i = extractFromRequest(req); if (i.equals(lastNumber.
17、get() encodeIntoResponse(resp, lastFactors.get() ); else BigInteger factors = factor(i); lastNumber.set(i); lastFactors.set(factors); encodeIntoResponse(resp, factors); lastNumber和lastFactors之間具有關(guān)系:lastFactors = factor(lastNumber) =使用lock來解決!假設(shè)lastNumber和lastFactors之間沒有關(guān)系,是否仍然有問題?2022-7-1Java內(nèi)存模型 管理
18、多個線程對共享內(nèi)存(對象)的訪問方式 多個線程共享對象,因而具有競爭關(guān)系 通過同步控制來避免出現(xiàn)不可預(yù)料的問題 計算結(jié)果被覆蓋 讀取過時的結(jié)果 相互等待死鎖 對象狀態(tài)被破壞 計算結(jié)果不能被其他線程及時獲得 等等2022-7-116ThreadJava內(nèi)存的管理層次ThreadCacheShared MemoryCachecodecodeuse/assignstorewriteloadread2022-7-117共享對象訪問的關(guān)鍵問題 讀寫訪問沖突 問題表現(xiàn):共享對象的狀態(tài)更新被覆蓋;讀取的狀態(tài)不完整等 根本原因:一個線程的“寫訪問”還未做完,另一個線程進行“寫訪問”或者“讀訪問” 狀態(tài)更新延遲
19、 沒有讀寫沖突(比如寫動作本身就是原子動作),但是讀操作無法及時獲得狀態(tài)的更新18public class Novisibility private static boolean ready=false;private static int number=0;private static class ReaderThread extends Thread public void run() while (!ready)Thread.yield();System.out.println(number);public static void main(String args) ReaderThre
20、ad r1 = new ReaderThread();r1.start();ready = true;number = 10;ReaderThread r2 = new ReaderThread();r2.start();number = 42;2022-7-1通過鎖解決共享對象訪問問題x = 1unlock MThread 1lock Mi = xThread 2lock My = 1unlock Mj = yprogramorderlocksyncprogramorderEverything happened before unlocking M is visible to everyth
21、ing after acquiring the lock on M注意兩個鎖注意兩個鎖M必須必須關(guān)聯(lián)到相同的對象關(guān)聯(lián)到相同的對象2022-7-119通過volatile來解決visibility問題20ThreadThreadCacheShared MemoryCachecodecodeuse/assignstorewriteloadreadvolatile private int count;2022-7-1死鎖問題 兩個線程互相等待對方持有的鎖來進行往下執(zhí)行,導(dǎo)致這兩個線程死鎖 不一定必然導(dǎo)致程序不響應(yīng),但是會導(dǎo)致某些功能不響應(yīng)21func() synchronized (obj1) do
22、 something s_obj.method(); public synchronized method() do somethingpublic synchronized method2() do something x.func();Thread 1Thread 22022-7-1共享對象的線程安全問題 共享是產(chǎn)生安全問題的根本 程序中有多種操作會產(chǎn)生對象共享 參數(shù)傳遞 返回值 使用公共可訪問對象的賦值 在分析一個類是否存在線程安全問題時,需要分析它會被哪些線程共享 特別需要關(guān)注一種情況:對象發(fā)布(Object Publication)222022-7-1對象發(fā)布與狀態(tài)失控 對象發(fā)布 把
23、對象“丟進”外部直接可訪問的集合中 把對象傳遞入另外一個類的方法中 把對象返回到外部 在單線程程序中,對象發(fā)布不會影響執(zhí)行結(jié)果 多線程程序必須跟蹤發(fā)布出去的每個對象 確保對其訪問的線程之間的執(zhí)行順序得到控制 否則,稱為狀態(tài)失控23class UnsafeStates private String states = new String AK, AL .; public String getStates() return states; 2022-7-1對象發(fā)布與狀態(tài)失控 我們必須做對象引用分析 數(shù)據(jù)流分析的一種 得到對象傳遞引用鏈:方法代碼區(qū)塊 處于同一條傳遞引用鏈上的代碼區(qū)塊如果跨越多個線程
24、,則都需要進行同步控制,否則就會產(chǎn)生共享對象狀態(tài)失控-線程不安全24public class Student private Vector courseList; private int id; public Student(int stuID) courseList = new Vector; id = stuID; public Vector get() return courseList; public boolean append(Course c) check whether c already exists in the list if(exist) return false; c
25、ourseList.append(c);return true; other methodspublic class Manager private Vector studentList; public void manage(int stuID) retrieve the student by the stuID list = student.get(); for (Course c: list) if(c.matches() c.update(); public boolean selectCourse(int stuID, Course c) retrieve the student b
26、y the stuID return student.append(c); 2022-7-1如何確保線程安全 使用不可變對象 使用final來強制限制對屬性成員的修改 要小心對可變對象的引用 使用可變對象 操作的原子性 共享對象要始終處于嚴(yán)密控制之下 不能直接return出去 讀、寫訪問的互斥控制 更改的及時可見 設(shè)置同步控制范圍25public class Board /推箱子面板 private final Set boxList; public Board() while() Box box = new Box(.); boxList.add(box); public Box get(P
27、osition p) box = . /retrieve a box according to p return box; public void draw() draw all the boxes in the board 2022-7-1如何確保線程安全 同步控制范圍 方法中代碼塊同步:synchronized(e) 每個對象默認(rèn)都有唯一的一個鎖 整個方法同步:public synchronized xxx method() 使用的是什么鎖? 同步控制范圍越大,其他線程等待時間就會越長 性能問題 盡量減少鎖的使用,盡量縮小鎖控制的范圍262022-7-1如何確保線程安全 無法修改一個非th
28、read-safe類的實現(xiàn)時怎么辦? 使用thread-safe wrapper-Monitor Pattern 設(shè)計一個線程安全Wrapper類,管理對目標(biāo)類對象的訪問 Wrapper類提供線程安全的方法來訪問所管理的對象(delegation)public class A private int value; private boolean odd; public A() value = 0; odd = false; public void increase(int x) value += x; if(x%2 =1 | x%2 = -1) odd = true; else odd = f
29、alse; public class SafeA private A a; public SafeA() a = new A(); public synchronized void increase(int x) a.increase(x); 2022-7-127確保線程安全的設(shè)計 識別形成對象狀態(tài)的域變量 關(guān)注所屬關(guān)系(ownership):即哪些類擁有/管理相應(yīng)的對象 一個對象可能由不同的類擁有,形成shared ownership產(chǎn)生共享 識別對象狀態(tài)需滿足的約束 狀態(tài)變量獨立 狀態(tài)變量不獨立 定義同步策略來管理對該對象的并發(fā)訪問 Backward analysis: 從對象出發(fā),循著o
30、wnership逆向分析,直至thread 確保對象的狀態(tài)約束在任何線程的訪問中都能滿足2022-7-128確保線程安全的設(shè)計 同步策略 同步控制哪些對象的訪問 被多個線程共享的任何可變對象 誰來負(fù)責(zé)同步控制 共享對象自身 使用共享對象的對象或線程 使用什么鎖 使用共享對象的this 使用共享對象所管理的局部對象鎖 使用傳遞參數(shù)對象鎖使用傳遞參數(shù)對象鎖 同步控制范圍 方法級別 語句塊級別29public class A public void func(Object x) synchronized(x) do something public void run() t = new SomeClass(); a.func(t); .public void run() y = new SomeClass(); a.func(y); .Thread 1Thread 2a2022-7-1確保線程安全的設(shè)計 歸結(jié)起來
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 建筑行業(yè)材料購銷協(xié)議書
- 紅酒采購合同實例
- 物流運輸海外發(fā)展框架
- 給排水工程招投標(biāo)評估報告
- 寧波住宅交易契約范本
- 招標(biāo)文件附件解析詳解
- 家校共管小學(xué)生放學(xué)安全家長信
- 廢紙購銷協(xié)議樣本
- 靈活擴展能力外包服務(wù)合同
- 碎石購銷合同格式范例
- 導(dǎo)醫(yī)接待與患者情緒管理
- 化工行業(yè)基礎(chǔ)知識培訓(xùn)課件
- 斜拉橋施工技術(shù)
- 《影視行業(yè)無形資產(chǎn)評估的案例分析-以華誼兄弟為例》12000字
- 新課標(biāo)下小學(xué)美術(shù)課程設(shè)計
- 國開電大操作系統(tǒng)-Linux系統(tǒng)使用-實驗報告
- 電氣技術(shù)協(xié)議
- 香煙過濾嘴問題論文
- 第五單元整體教學(xué)課件-七年級語文上冊
- 中學(xué)生主題班會課題:科學(xué)素養(yǎng)與創(chuàng)新能力培養(yǎng)
- 余華讀書分享名著導(dǎo)讀《文城》
評論
0/150
提交評論