淺析Java 并發(fā)編程中的synchronized
synchronized關(guān)鍵字,我們一般稱之為“同步鎖”,用它來(lái)修飾需要同步的方法和需要同步代碼塊,默認(rèn)是當(dāng)前對(duì)象作為鎖的對(duì)象。在用synchronized修飾類時(shí)(或者修飾靜態(tài)方法),默認(rèn)是當(dāng)前類的Class對(duì)象作為鎖的對(duì)象,故存在著方法鎖、對(duì)象鎖、類鎖這樣的概念。
一、沒(méi)有設(shè)置線程同步的情況
先給出以下代碼感受下代碼執(zhí)行的時(shí)候?yàn)槭裁葱枰??代碼可能比較枯燥,配上業(yè)務(wù)理解起來(lái)就會(huì)舒服很多,學(xué)生軍訓(xùn),有三列,每列5人,需要報(bào)數(shù),每個(gè)線程負(fù)責(zé)每一列報(bào)數(shù)。
class SynchronizedExample { protected static int num = 0; protected void numberOff() { for(int i=0; i<5; i++) { num++; System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num); } } } public class SynchronizedTest { public static void main(String[] args) throws InterruptedException { SynchronizedExample se = new SynchronizedExample(); for(int i=1; i<=3; i++) { new Thread( ()-> {se.numberOff();}, "線程"+i).start(); } } }
執(zhí)行結(jié)果如下:
線程1:1
線程2:2
線程1:3
線程3:4
.......
之所以出現(xiàn)這種情況,是因?yàn)槿齻€(gè)線程是異步的,沒(méi)有同步。
對(duì)應(yīng)的業(yè)務(wù)場(chǎng)景就是,在第一列沒(méi)有完成報(bào)數(shù)的時(shí)候,其他隊(duì)列搶報(bào)了,這在現(xiàn)實(shí)中是不允許的,所以需要類似于synchronized等具有同步功能的關(guān)鍵字粉末登場(chǎng)。
二、方法同步鎖
當(dāng)報(bào)數(shù)方法加上synchronized關(guān)鍵字之后,就會(huì)一列一列的報(bào)數(shù)。
protected synchronized void numberOff() { for(int i=0; i<5; i++) { num++; System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num); } }
執(zhí)行結(jié)果如下:
線程1:1
線程1:2
線程1:3
線程1:4
......
寫到這里還是要從技術(shù)層面講下原理,當(dāng)一個(gè)線程執(zhí)行帶有synchronized關(guān)鍵字的方法時(shí),該線程會(huì)在該方法處設(shè)置一個(gè)鎖(其他線程打不開這個(gè)鎖,只能在外邊等該線程釋放掉該鎖,一般都是執(zhí)行完所有代碼后主動(dòng)釋放鎖),表示此方法是當(dāng)前線程獨(dú)占的,對(duì)應(yīng)到上述業(yè)務(wù)中就是一次只能有一個(gè)隊(duì)列報(bào)數(shù)。
三、對(duì)象鎖
改進(jìn)后的代碼用到了一個(gè)對(duì)象鎖,該對(duì)象鎖默認(rèn)是當(dāng)前對(duì)象,上述代碼等同于以下代碼:
protected void numberOff() { synchronized (this) { for (int i = 0; i < 5; i++) { num++; System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num); } } }
當(dāng)多個(gè)線程用一個(gè)對(duì)象鎖,各個(gè)線程可以達(dá)到同步的作用,如果每個(gè)線程都用自己的對(duì)象鎖,那么synchronized就失去了同步的作用。如以下代碼:
class SynchronizedExample { protected static int num = 0; protected void numberOff() { synchronized (this) { for (int i = 0; i < 5; i++) { num++; System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num); } } } } public class SynchronizedTest { public static void main(String[] args) throws InterruptedException { SynchronizedExample se = new SynchronizedExample(); for(int i=1; i<=3; i++) { new Thread( ()-> {new SynchronizedExample().numberOff();}, "隊(duì)列"+i).start(); } } }
執(zhí)行結(jié)果如下:
線程1:1
線程2:2
線程1:3
線程3:4
.......
有讀者會(huì)說(shuō)不同線程執(zhí)行的是不同對(duì)象中的方法,肯定達(dá)不到同步的效果,也對(duì),也很有道理,接著看如下代碼:
class SynchronizedExample { protected static int num = 0; protected void numberOff(Object lock) { synchronized (lock) { for (int i = 0; i < 5; i++) { num++; System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num); } } } } public class SynchronizedTest { public static void main(String[] args) throws InterruptedException { SynchronizedExample se = new SynchronizedExample(); for(int i=1; i<=3; i++) { new Thread( ()-> {se.numberOff(new Object());}, "隊(duì)列"+i).start(); } } }
執(zhí)行結(jié)果如下:
線程1:1
線程2:2
線程1:3
線程3:4
.......
四、類鎖
對(duì)于上述問(wèn)題,讀者應(yīng)該得出一個(gè)結(jié)論,要想達(dá)到同步的效果,必須用同一個(gè)鎖,此時(shí)類鎖可以粉末登場(chǎng)??慈缦麓a:
protected void numberOff(Object lock) { synchronized (SynchronizedExample.class) { for (int i = 0; i < 5; i++) { num++; System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num); } } }
上述代碼可以達(dá)到同步的效果。
五、靜態(tài)鎖
靜態(tài)鎖是針對(duì)靜態(tài)方法而言,當(dāng)一個(gè)靜態(tài)方法中有synchronized關(guān)鍵字時(shí),默認(rèn)的是使用當(dāng)前類字節(jié)碼對(duì)象作為鎖。代碼示例如下:
class SynchronizedExample { protected static int num = 0; protected synchronized static void numberOff() { for (int i = 0; i < 5; i++) { num++; System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num); } } } public class SynchronizedTest { public static void main(String[] args) throws InterruptedException { for (int i = 1; i <= 3; i++) { new Thread(() -> { new SynchronizedExample().numberOff(); }, "隊(duì)列" + i).start(); } } }
六、線程池實(shí)現(xiàn)
最后用線程池將上述代碼寫一下
package ioo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class SynchronizedExample { protected static int num = 0; protected synchronized static void numberOff() { for (int i = 0; i < 5; i++) { num++; System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num); } } } public class SynchronizedTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); for(int i=1; i<=3; i++) { executorService.execute(() -> new SynchronizedExample().numberOff()); } } }
以上就是淺析Java 并發(fā)編程中的synchronized的詳細(xì)內(nèi)容,更多關(guān)于Java 并發(fā)編程 synchronized的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 下
- Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 上
- Java并發(fā)之synchronized實(shí)現(xiàn)原理深入理解
- java并發(fā)編程之深入理解Synchronized的使用
- 詳解Java并發(fā)編程之內(nèi)置鎖(synchronized)
- 淺析java并發(fā)中的Synchronized關(guān)鍵詞
- Java并發(fā) synchronized鎖住的內(nèi)容解析
- 詳解java并發(fā)編程(2) --Synchronized與Volatile區(qū)別
- 詳解Java利用同步塊synchronized()保證并發(fā)安全
- java并發(fā)之synchronized
相關(guān)文章
java實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04spring動(dòng)態(tài)注冊(cè)bean?AOP失效原理解析
這篇文章主要為大家介紹了spring動(dòng)態(tài)注冊(cè)bean使AOP失效原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07java HashMap通過(guò)value反查key的代碼示例
本文講解了java HashMap通過(guò)value反查key的方法,直接提供代碼供大家參考使用2013-11-11如何在spring boot中進(jìn)行參數(shù)校驗(yàn)示例詳解
這篇文章主要介紹了如何在spring-boot中進(jìn)行參數(shù)校驗(yàn)及l(fā)ombok的使用詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05Java中==符號(hào)與equals()的使用詳解(測(cè)試兩個(gè)變量是否相等)
下面小編就為大家?guī)?lái)一篇Java中==符號(hào)與equals()的使用詳解(測(cè)試兩個(gè)變量是否相等)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07