java多線程-同步塊實例講解
java多線程-同步塊
Java 同步塊(synchronized block)用來標記方法或者代碼塊是同步的。Java 同步塊用來避免競爭。本文介紹以下內(nèi)容:
- Java 同步關(guān)鍵字(synchronzied)
- 實例方法同步
- 靜態(tài)方法同步
- 實例方法中同步塊
- 靜態(tài)方法中同步塊
- Java 同步示例
Java 同步關(guān)鍵字(synchronized)
Java 中的同步塊用 synchronized 標記。同步塊在 Java 中是同步在某個對象上。所有同步在一個對象上的同步塊在同時只能被一個線程進入并執(zhí)行操作。所有其他等待進入該同步塊的線程將被阻塞,直到執(zhí)行該同步塊中的線程退出。
有四種不同的同步塊:
- 實例方法
- 靜態(tài)方法
- 實例方法中的同步塊
- 靜態(tài)方法中的同步塊
上述同步塊都同步在不同對象上。實際需要那種同步塊視具體情況而定。
實例方法同步
下面是一個同步的實例方法:
public synchronized void add(int value){ this.count += value; }
靜態(tài)方法同步
靜態(tài)方法同步和實例方法同步方法一樣,也使用 synchronized 關(guān)鍵字。Java 靜態(tài)方法同步如下示例:
public static synchronized void add(int value){ count += value; }
同樣,這里 synchronized 關(guān)鍵字告訴 Java 這個方法是同步的。
靜態(tài)方法的同步是指同步在該方法所在的類對象上。因為在 Java 虛擬機中一個類只能對應(yīng)一個類對象,所以同時只允許一個線程執(zhí)行同一個類中的靜態(tài)同步方法。
對于不同類中的靜態(tài)同步方法,一個線程可以執(zhí)行每個類中的靜態(tài)同步方法而無需等待。不管類中的那個靜態(tài)同步方法被調(diào)用,一個類只能由一個線程同時執(zhí)行。
實例方法中的同步塊
有時你不需要同步整個方法,而是同步方法中的一部分。Java 可以對方法的一部分進行同步。
在非同步的 Java 方法中的同步塊的例子如下所示:
public void add(int value){ synchronized(this){ this.count += value; } }
示例使用 Java 同步塊構(gòu)造器來標記一塊代碼是同步的。該代碼在執(zhí)行時和同步方法一樣。
注意 Java 同步塊構(gòu)造器用括號將對象括起來。在上例中,使用了“this”,即為調(diào)用 add 方法的實例本身。在同步構(gòu)造器中用括號括起來的對象叫做監(jiān)視器對象。上述代碼使用監(jiān)視器對象同步,同步實例方法使用調(diào)用方法本身的實例作為監(jiān)視器對象。
一次只有一個線程能夠在同步于同一個監(jiān)視器對象的 Java 方法內(nèi)執(zhí)行。
下面兩個例子都同步他們所調(diào)用的實例對象上,因此他們在同步的執(zhí)行效果上是等效的。
public class MyClass { public synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public void log2(String msg1, String msg2){ synchronized(this){ log.writeln(msg1); log.writeln(msg2); } } }
在上例中,每次只有一個線程能夠在兩個同步塊中任意一個方法內(nèi)執(zhí)行。
如果第二個同步塊不是同步在 this 實例對象上,那么兩個方法可以被線程同時執(zhí)行。
靜態(tài)方法中的同步塊
和上面類似,下面是兩個靜態(tài)方法同步的例子。這些方法同步在該方法所屬的類對象上。
public class MyClass { public static synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ log.writeln(msg1); log.writeln(msg2); } } }
這兩個方法不允許同時被線程訪問。
如果第二個同步塊不是同步在 MyClass.class 這個對象上。那么這兩個方法可以同時被線程訪問。
Java 同步實例
在下面例子中,啟動了兩個線程,都調(diào)用 Counter 類同一個實例的 add 方法。因為同步在該方法所屬的實例上,所以同時只能有一個線程訪問該方法。
public class Counter{ long count = 0; public synchronized void add(long value){ this.count += value; } } public class CounterThread extends Thread{ protected Counter counter = null; public CounterThread(Counter counter){ this.counter = counter; } public void run() { for(int i=0; i<10; i++){ counter.add(i); } } } public class Example { public static void main(String[] args){ Counter counter = new Counter(); Thread threadA = new CounterThread(counter); Thread threadB = new CounterThread(counter); threadA.start(); threadB.start(); } }
創(chuàng)建了兩個線程。他們的構(gòu)造器引用同一個 Counter 實例。Counter.add 方法是同步在實例上,是因為 add 方法是實例方法并且被標記上 synchronized 關(guān)鍵字。因此每次只允許一個線程調(diào)用該方法。另外一個線程必須要等到第一個線程退出 add()方法時,才能繼續(xù)執(zhí)行方法。
如果兩個線程引用了兩個不同的 Counter 實例,那么他們可以同時調(diào)用 add()方法。這些方法調(diào)用了不同的對象,因此這些方法也就同步在不同的對象上。這些方法調(diào)用將不會被阻塞。如下面這個例子所示:
public class Example { public static void main(String[] args){ Counter counterA = new Counter(); Counter counterB = new Counter(); Thread threadA = new CounterThread(counterA); Thread threadB = new CounterThread(counterB); threadA.start(); threadB.start(); } }
注意這兩個線程,threadA 和 threadB,不再引用同一個 counter 實例。CounterA 和 counterB 的 add 方法同步在他們所屬的對象上。調(diào)用 counterA 的 add 方法將不會阻塞調(diào)用 counterB 的 add 方法。
以上就是對Java 多線程同步塊的知識講解,后續(xù)繼續(xù)補充相關(guān)資料,謝謝大家對本站的支持!
相關(guān)文章
springboot使用redisRepository和redistemplate操作redis的過程解析
本文給大家介紹springboot整合redis/分別用redisRepository和redistemplate操作redis,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2022-05-05Java中對list map根據(jù)map某個key值進行排序的方法
今天小編就為大家分享一篇Java中對list map根據(jù)map某個key值進行排序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07java實現(xiàn)多人聊天工具(socket+多線程)
這篇文章主要為大家詳細介紹了java實現(xiàn)多人聊天工具,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08如何解決IDEA中JSP頁面部分出現(xiàn)綠色背景色問題
這篇文章主要介紹了如何解決IDEA中JSP頁面部分出現(xiàn)綠色背景色問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12