摘要:同步塊用來避免競爭。實際需要那種同步塊視具體情況而定。在非同步的方法中的同步塊的例子如下所示示例使用同步塊構造器來標記一塊代碼是同步的。在同步構造器中用括號括起來的對象叫做監(jiān)視器對象。他們的構造器引用同一個實例。
Java 同步塊(synchronized block)用來標記方法或者代碼塊是同步的。Java同步塊用來避免競爭。本文介紹以下內(nèi)容:
Java同步關鍵字(synchronzied)
實例方法同步
靜態(tài)方法同步
實例方法中同步塊
靜態(tài)方法中同步塊
Java同步示例
Java同步關鍵字(synchronized)Java中的同步塊用synchronized標記。同步塊在Java中是同步在某個對象上。所有同步在一個對象上的同步塊在同時只能被一個線程進入并執(zhí)行操作。所有其他等待進入該同步塊的線程將被阻塞,直到執(zhí)行該同步塊中的線程退出。
有四種不同的同步塊:
實例方法
靜態(tài)方法
實例方法中的同步塊
靜態(tài)方法中的同步塊
上述同步塊都同步在不同對象上。實際需要那種同步塊視具體情況而定。
實例方法同步下面是一個同步的實例方法:
public synchronized void add(int value){ this.count += value; }
注意在方法聲明中同步(synchronized?)關鍵字。這告訴Java該方法是同步的。
Java實例方法同步是同步在擁有該方法的對象上。這樣,每個實例其方法同步都同步在不同的對象上,即該方法所屬的實例。只有一個線程能夠在實例方法同步塊中運行。如果有多個實例存在,那么一個線程一次可以在一個實例同步塊中執(zhí)行操作。一個實例一個線程。
靜態(tài)方法同步靜態(tài)方法同步和實例方法同步方法一樣,也使用synchronized?關鍵字。Java靜態(tài)方法同步如下示例:
public static synchronized void add(int value){ count += value; }
同樣,這里synchronized?關鍵字告訴Java這個方法是同步的。
靜態(tài)方法的同步是指同步在該方法所在的類對象上。因為在Java虛擬機中一個類只能對應一個類對象,所以同時只允許一個線程執(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同步塊構造器來標記一塊代碼是同步的。該代碼在執(zhí)行時和同步方法一樣。
注意Java同步塊構造器用括號將對象括起來。在上例中,使用了“this”,即為調(diào)用add方法的實例本身。在同步構造器中用括號括起來的對象叫做監(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)建了兩個線程。他們的構造器引用同一個Counter實例。Counter.add方法是同步在實例上,是因為add方法是實例方法并且被標記上synchronized關鍵字。因此每次只允許一個線程調(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 Synchronized Blocks
作者 Jakob Jenkov
譯者 李同杰
via ifeve
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64070.html
摘要:線程通信的目標是使線程間能夠互相發(fā)送信號。但是,這個標志已經(jīng)被第一個喚醒的線程清除了,所以其余醒來的線程將回到等待狀態(tài),直到下次信號到來。如果方法調(diào)用,而非,所有等待線程都會被喚醒并依次檢查信號值。 線程通信的目標是使線程間能夠互相發(fā)送信號。另一方面,線程通信使線程能夠等待其他線程的信號。 showImg(http://segmentfault.com/img/bVbPLD); 例...
摘要:可重入的意思是線程可以重復獲得它已經(jīng)持有的鎖。如果一個線程持有某個管程對象上的鎖,那么它就有權訪問所有在該管程對象上同步的塊。下面這個鎖的實現(xiàn)是不可重入的如果一個線程在兩次調(diào)用間沒有調(diào)用方法,那么第二次調(diào)用就會被阻塞,這就出現(xiàn)了重入鎖死。 重入鎖死與死鎖和嵌套管程鎖死非常相似。鎖和讀寫鎖兩篇文章中都有涉及到重入鎖死的問題。 showImg(http://segmentfault.co...
摘要:死亡狀態(tài)線程退出有可能是正常執(zhí)行完成也有可能遇見異常退出。類有新建與死亡狀態(tài)返回其余狀態(tài)返回判斷線程是否存活。線程因某些原因進入阻塞狀態(tài)。執(zhí)行同步代碼塊的過程中執(zhí)行了當前線程放棄開始睡眠進入就緒狀態(tài)但是不會釋放鎖。 【java內(nèi)存模型簡介 JVM中存在一個主存區(qū)(Main Memory或Java Heap Memory),Java中所有變量都是存在主存中的,對于所有線程進行共享,而每個...
摘要:在中一般來說通過來創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細原理解析 - 后端 - 掘金今天我們來研究學習一下AbstractQueuedSynchronizer類的相關原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...
閱讀 3655·2023-04-26 02:07
閱讀 3165·2021-09-22 15:55
閱讀 2540·2021-07-26 23:38
閱讀 3122·2019-08-29 15:16
閱讀 2011·2019-08-29 11:16
閱讀 1755·2019-08-29 11:00
閱讀 3590·2019-08-26 18:36
閱讀 3167·2019-08-26 13:32