怎樣用eclipse做網(wǎng)站品牌營(yíng)銷推廣方案怎么做
目錄
前言
一、確定需要多個(gè)鎖的場(chǎng)景
1.獨(dú)立資源保護(hù)
2.部分依賴資源
二、避免死鎖
三、鎖粒度與并發(fā)性能
1.?粗粒度鎖定
2.細(xì)粒度鎖定
四、設(shè)計(jì)策略:減少資源依賴
1.資源分離
2.無(wú)鎖設(shè)計(jì)
3.鎖合并
五、Demo講解
總結(jié):
前言
????????當(dāng)多個(gè)線程需要操作共享資源時(shí),為了確保數(shù)據(jù)的一致性和避免競(jìng)爭(zhēng)條件,通常會(huì)使用多個(gè)鎖來(lái)進(jìn)行同步。這種情況下,如何正確使用多個(gè)鎖成為一個(gè)復(fù)雜而關(guān)鍵的問(wèn)題。下面是一篇十分詳細(xì)的博客,介紹多線程多鎖場(chǎng)景下的最佳實(shí)踐和注意事項(xiàng)。
一、確定需要多個(gè)鎖的場(chǎng)景
1.獨(dú)立資源保護(hù)
- 定義:當(dāng)不同的資源(例如文件、數(shù)據(jù)庫(kù)連接等)由不同的鎖保護(hù)時(shí)。
- 示例:一個(gè)線程需要讀取文件A并寫(xiě)入文件B,而另一個(gè)線程讀取文件B并寫(xiě)入文件A,這兩個(gè)操作可以分別使用不同的鎖。
2.部分依賴資源
- 定義:多個(gè)資源之間存在某種程度的依賴關(guān)系,但操作它們的線程可能不會(huì)同時(shí)訪問(wèn)所有資源。
- 示例:兩個(gè)線程分別操作兩個(gè)互相有數(shù)據(jù)交換的隊(duì)列,可分別對(duì)兩個(gè)隊(duì)列加鎖,但在交換數(shù)據(jù)時(shí)需要特別小心處理鎖的順序。
二、避免死鎖
死鎖是多線程編程中常見(jiàn)的問(wèn)題,特別是在使用多個(gè)鎖的情況下更容易發(fā)生。要避免死鎖,可以采取以下策略:
- 按順序獲取鎖:對(duì)多個(gè)資源使用相同的順序獲取鎖,以避免循環(huán)等待。
- 設(shè)置超時(shí)時(shí)間:在獲取鎖的過(guò)程中設(shè)置超時(shí)時(shí)間,一段時(shí)間后未能獲取到鎖就放棄或重試。
- 使用高級(jí)同步工具:比如信號(hào)量(Semaphores)或條件變量(Condition Variables),它們提供了更靈活的同步機(jī)制,有助于避免死鎖。
三、鎖粒度與并發(fā)性能
1.?粗粒度鎖定
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎ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ù)庫(kù)拆分為多個(gè)獨(dú)立的部分,每個(gè)部分由不同的線程和鎖管理。
2.無(wú)鎖設(shè)計(jì)
- 定義:通過(guò)無(wú)鎖編程(如使用原子操作)來(lái)完全避免鎖。
- 示例:使用Java的
AtomicInteger
類進(jìn)行計(jì)數(shù)器操作。
3.鎖合并
- 定義:在某些情況下,將多個(gè)鎖合并為一個(gè)鎖,以簡(jiǎn)化鎖管理。
- 示例:如果兩個(gè)資源總是一起被訪問(wèn),可以用一個(gè)鎖來(lái)保護(hù)它們。
五、Demo講解
package com.ctb.demo;/*** 關(guān)鍵字synchronized取得的鎖都是對(duì)象鎖,而不是把一段代碼(方法)當(dāng)做鎖* 所以代碼中哪個(gè)線程先執(zhí)行synchronized關(guān)鍵字的方法,哪個(gè)線程就持有該方法所屬對(duì)象的鎖(Lock),* * 在靜態(tài)方法上加synchronized關(guān)鍵字,表示鎖定.class類,類一級(jí)別的鎖(獨(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取得的鎖都是對(duì)象鎖,而不是把一段代碼(方法)當(dāng)做鎖* 所以代碼中哪個(gè)線程先執(zhí)行synchronized關(guān)鍵字的方法,哪個(gè)線程就持有該方法所屬對(duì)象的鎖(Lock),* * 在靜態(tài)方法上加synchronized關(guān)鍵字,表示鎖定.class類,類一級(jí)別的鎖(獨(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取得的鎖都是對(duì)象鎖,而不是把一段代碼(方法)當(dāng)做鎖
所以代碼中哪個(gè)線程先執(zhí)行synchronized關(guān)鍵字的方法,哪個(gè)線程就持有該方法所屬對(duì)象的鎖(Lock),
在靜態(tài)方法上加synchronized關(guān)鍵字,表示鎖定.class類,類一級(jí)別的鎖(獨(dú)占.class類)