怎樣用eclipse做網(wǎng)站品牌營銷推廣方案怎么做
目錄
前言
一、確定需要多個(gè)鎖的場景
1.獨(dú)立資源保護(hù)
2.部分依賴資源
二、避免死鎖
三、鎖粒度與并發(fā)性能
1.?粗粒度鎖定
2.細(xì)粒度鎖定
四、設(shè)計(jì)策略:減少資源依賴
1.資源分離
2.無鎖設(shè)計(jì)
3.鎖合并
五、Demo講解
總結(jié):
前言
????????當(dāng)多個(gè)線程需要操作共享資源時(shí),為了確保數(shù)據(jù)的一致性和避免競爭條件,通常會使用多個(gè)鎖來進(jìn)行同步。這種情況下,如何正確使用多個(gè)鎖成為一個(gè)復(fù)雜而關(guān)鍵的問題。下面是一篇十分詳細(xì)的博客,介紹多線程多鎖場景下的最佳實(shí)踐和注意事項(xiàng)。
一、確定需要多個(gè)鎖的場景
1.獨(dú)立資源保護(hù)
- 定義:當(dāng)不同的資源(例如文件、數(shù)據(jù)庫連接等)由不同的鎖保護(hù)時(shí)。
- 示例:一個(gè)線程需要讀取文件A并寫入文件B,而另一個(gè)線程讀取文件B并寫入文件A,這兩個(gè)操作可以分別使用不同的鎖。
2.部分依賴資源
- 定義:多個(gè)資源之間存在某種程度的依賴關(guān)系,但操作它們的線程可能不會同時(shí)訪問所有資源。
- 示例:兩個(gè)線程分別操作兩個(gè)互相有數(shù)據(jù)交換的隊(duì)列,可分別對兩個(gè)隊(duì)列加鎖,但在交換數(shù)據(jù)時(shí)需要特別小心處理鎖的順序。
二、避免死鎖
死鎖是多線程編程中常見的問題,特別是在使用多個(gè)鎖的情況下更容易發(fā)生。要避免死鎖,可以采取以下策略:
- 按順序獲取鎖:對多個(gè)資源使用相同的順序獲取鎖,以避免循環(huán)等待。
- 設(shè)置超時(shí)時(shí)間:在獲取鎖的過程中設(shè)置超時(shí)時(shí)間,一段時(shí)間后未能獲取到鎖就放棄或重試。
- 使用高級同步工具:比如信號量(Semaphores)或條件變量(Condition Variables),它們提供了更靈活的同步機(jī)制,有助于避免死鎖。
三、鎖粒度與并發(fā)性能
1.?粗粒度鎖定
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡單,易于理解和維護(hù)。
- 缺點(diǎn):可能導(dǎo)致大量線程等待,從而降低并發(fā)性能。
- 示例:一個(gè)單一的大鎖保護(hù)整個(gè)資源集合。
2.細(xì)粒度鎖定
- 優(yōu)點(diǎn):提高并發(fā)性能,因?yàn)殒i的范圍縮小,減少了線程等待的概率。
- 缺點(diǎn):實(shí)現(xiàn)復(fù)雜,需要更精細(xì)的設(shè)計(jì)和管理。
- 示例:為每個(gè)獨(dú)立資源(或資源的部分)使用單獨(dú)的小鎖。
四、設(shè)計(jì)策略:減少資源依賴
1.資源分離
- 定義:盡量將共享資源劃分為獨(dú)立的部分,使得每個(gè)部分只需一個(gè)鎖。
- 示例:將一個(gè)大型數(shù)據(jù)庫拆分為多個(gè)獨(dú)立的部分,每個(gè)部分由不同的線程和鎖管理。
2.無鎖設(shè)計(jì)
- 定義:通過無鎖編程(如使用原子操作)來完全避免鎖。
- 示例:使用Java的
AtomicInteger
類進(jìn)行計(jì)數(shù)器操作。
3.鎖合并
- 定義:在某些情況下,將多個(gè)鎖合并為一個(gè)鎖,以簡化鎖管理。
- 示例:如果兩個(gè)資源總是一起被訪問,可以用一個(gè)鎖來保護(hù)它們。
五、Demo講解
package com.ctb.demo;/*** 關(guān)鍵字synchronized取得的鎖都是對象鎖,而不是把一段代碼(方法)當(dāng)做鎖* 所以代碼中哪個(gè)線程先執(zhí)行synchronized關(guān)鍵字的方法,哪個(gè)線程就持有該方法所屬對象的鎖(Lock),* * 在靜態(tài)方法上加synchronized關(guān)鍵字,表示鎖定.class類,類一級別的鎖(獨(dú)占.class類)* * @author biao** 2024年*/
public class MyThread2 {private int num =0;public synchronized void printNum(String tag) {try {if (tag.equals("a")) {num=100;System.out.println("tag a,set num over!");Thread.sleep(1000);}else {num = 200;System.out.println("tag b,set num over!");}System.out.println("tag" + tag + "," + "num" + num);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {final MyThread2 m1 = new MyThread2();final MyThread2 m2 = new MyThread2();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {m1.printNum("a");}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {m2.printNum("b");}});t1.start();t2.start();}}
結(jié)果:
package com.ctb.demo;/*** 關(guān)鍵字synchronized取得的鎖都是對象鎖,而不是把一段代碼(方法)當(dāng)做鎖* 所以代碼中哪個(gè)線程先執(zhí)行synchronized關(guān)鍵字的方法,哪個(gè)線程就持有該方法所屬對象的鎖(Lock),* * 在靜態(tài)方法上加synchronized關(guān)鍵字,表示鎖定.class類,類一級別的鎖(獨(dú)占.class類)* * @author biao** 2024年2月28日-上午12:07:26*/
public class MyThread2 {private static int num =0;// staticpublic static synchronized void printNum(String tag) {try {if (tag.equals("a")) {num=100;System.out.println("tag a,set num over!");Thread.sleep(1000);}else {num = 200;System.out.println("tag b,set num over!");}System.out.println("tag" + tag + "," + "num" + num);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {final MyThread2 m1 = new MyThread2();final MyThread2 m2 = new MyThread2();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {m1.printNum("a");}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {m2.printNum("b");}});t1.start();t2.start();}}
結(jié)果:
總結(jié):
關(guān)鍵字synchronized取得的鎖都是對象鎖,而不是把一段代碼(方法)當(dāng)做鎖
所以代碼中哪個(gè)線程先執(zhí)行synchronized關(guān)鍵字的方法,哪個(gè)線程就持有該方法所屬對象的鎖(Lock),
在靜態(tài)方法上加synchronized關(guān)鍵字,表示鎖定.class類,類一級別的鎖(獨(dú)占.class類)