日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > java多線程、并發系列之 (synchronized)同步與加鎖機制

java多線程、并發系列之 (synchronized)同步與加鎖機制

來源:程序員人生   發布時間:2015-07-01 08:31:22 閱讀次數:5962次

Synchronized

Java中每一個對象都有1個內置鎖,當程序運行到非靜態的synchronized同步方法上時,自動取得與正在履行代碼類確當前實例(this實例)有關的鎖。取得1個對象的鎖也稱為獲得鎖、鎖定對象、在對象上鎖定或在對象上同步。

當程序運行到synchronized同步方法或代碼塊時才該對象鎖才起作用。

1個對象只有1個鎖。所以,如果1個線程取得該鎖,就沒有其他線程可以取得鎖,直到第1個線程釋放(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法或代碼塊,直到該鎖被釋放。

釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。

Java中的同步塊用synchronized標記。同步塊在Java中是同步在某個對象上。所有同步在1個對象上的同步塊在同時只能被1個線程進入并履行操作。所有其他等待進入該同步塊的線程將被阻塞,直到履行該同步塊中的線程退出。
有4種不同的同步塊:

1. 實例方法
2. 靜態方法
3. 實例方法中的同步塊
4. 靜態方法中的同步塊

上述同步塊都同步在不同對象上。實際需要那種同步塊視具體情況而定。
實例方法同步
下面是1個同步的實例方法:

public synchronized void add(int value){ this.count += value; }

注意在方法聲明中同步(synchronized )關鍵字。這告知Java該方法是同步的。
Java實例方法同步是同步在具有該方法的對象上。這樣,每一個實例其方法同步都同步在不同的對象上,即該方法所屬的實例。只有1個線程能夠在實例方法同步塊中運行。如果有多個實例存在,那末1個線程1次可以在1個實例同步塊中履行操作。1個實例1個線程。

靜態方法同步
靜態方法同步和實例方法同步方法1樣,也使用synchronized 關鍵字。Java靜態方法同步以下示例:

public static synchronized void add(int value){ count += value; }

一樣,這里synchronized 關鍵字告知Java這個方法是同步的。
靜態方法的同步是指同步在該方法所在的類對象上。由于在Java虛擬機中1個類只能對應1個類對象,所以同時只允許1個線程履行同1個類中的靜態同步方法。
對不同類中的靜態同步方法,1個線程可以履行每一個類中的靜態同步方法而無需等待。不管類中的那個靜態同步方法被調用,1個類只能由1個線程同時履行。

實例方法中的同步塊
有時你不需要同步全部方法,而是同步方法中的1部份。Java可以對方法的1部份進行同步。
在非同步的Java方法中的同步塊的例子以下所示:

public void add(int value){ synchronized(this){ this.count += value; } }

示例使用Java同步塊構造器來標記1塊代碼是同步的。該代碼在履行時和同步方法1樣。
注意Java同步塊構造器用括號將對象括起來。在上例中,使用了“this”,即為調用add方法的實例本身。在同步構造器中用括號括起來的對象叫做監視器對象。上述代碼使用監視器對象同步,同步實例方法使用調用方法本身的實例作為監視器對象。
1次只有1個線程能夠在同步于同1個監視器對象的Java方法內履行。
下面兩個例子都同步他們所調用的實例對象上,因此他們在同步的履行效果上是等效的。

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); } } }

在上例中,每次只有1個線程能夠在兩個同步塊中任意1個方法內履行。
如果第2個同步塊不是同步在this實例對象上,那末兩個方法可以被線程同時履行。
靜態方法中的同步塊
和上面類似,下面是兩個靜態方法同步的例子。這些方法同步在該方法所屬的類對象上。

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); } } }

這兩個方法不允許同時被線程訪問。
如果第2個同步塊不是同步在MyClass.class這個對象上。那末這兩個方法可以同時被線程訪問。

使用同步方法1些注意細節:

1、線程同步的目的是為了保護多個線程反問1個資源時對資源的破壞。
2、線程同步方法是通過鎖來實現,每一個對象都有切唯一1個鎖,這個鎖與1個特定的對象關聯,線程1旦獲得了對象鎖,其他訪問該對象的線程就沒法再訪問該對象的其他同步方法。
3、對靜態同步方法,鎖是針對這個類的,鎖對象是該類的Class對象。靜態和非靜態方法的鎖互不干預。1個線程取得鎖,當在1個同步方法中訪問另外對象上的同步方法時,會獲得這兩個對象鎖。
4、對同步,要時刻蘇醒在哪一個對象上同步,這是關鍵。
5、編寫線程安全的類,需要時刻注意對多個線程競爭訪問資源的邏輯和安全做出正確的判斷,對“原子”操作做出分析,并保證原子操作期間別的線程沒法訪問競爭資源。
6、當多個線程等待1個對象鎖時,沒有獲得到鎖的線程將產生阻塞。
7、死鎖是線程間相互等待鎖鎖釀成的,在實際中產生的幾率非常的小。

鎖機制:

在java 5.0之前,在調和對象同享的訪問時可使用的機制只有synchronized和volatile。java 5.0增加了1種新的機制ReentrantLock。與之條件到過的機制相反,ReentrantLock其實不是1種替換內置加鎖的方法,而是當內置加鎖機制不適用時,作為1種可選擇的高級功能。

Lock  接口的源碼:
public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock( long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition(); }

與內置加鎖機制不同,lock接口提供了1種無條件的、可輪詢的、定時的和可中斷的鎖獲得機制,所有的加鎖和解鎖方法都是顯示的,在Lock的實現中必須提供與內部鎖相同的內存可見性語義,但在加鎖語義、調度算法、順序保證和性能特性方面可以有所不同。

ReentrantLock實現了Lock接口,并提供了與synchronized相同的互斥性和內存可見性。

public class ReentrantLockextends Objectimplements Lock, Serializable

與synchronized1樣,ReentrantLock還提供了可重入的加鎖語義,與synchronized相比他還為處理鎖機制不可用性問題提供了更高的靈活性

為何要創建1種與內置鎖如此相近的新加鎖機制?

在大多數情況下,內置鎖都能夠很好的工作,但在功能上存在1些局限性,例如:沒法提供中斷1個正在等待獲得鎖的線程或沒法在要求獲得1個鎖時無窮等待下去。內置鎖必須在獲得該鎖的代碼中釋放,這雖然簡化了編碼工作(還能與異常處理操作很好的實現交互),但卻沒法實現非阻塞結構的加鎖規則。

使用Lock接口的標準情勢以下:

class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }

注意必須在finally中釋放鎖,由于如果在try中出現了異常,并且沒有在finally中進行鎖的釋放,那末該鎖就永久沒法釋放了。還需斟酌在try中拋出異常的情況,如果可能使對象處于某種不1致的狀態,那末就需要更多的try-catch或try-finally代碼快。

輪詢鎖和定時鎖

可定時的與可輪詢的鎖獲得模式是由tryLock方法實現的,與無條件的鎖獲得模式相比,它具有更完善的毛病恢復機制。
輪詢鎖:

利用tryLock來獲得兩個鎖,如果不能同時取得,那末回退并重新嘗試。

public boolean transferMoney(Account fromAcct, Account toAcct, DollarAmount amount, long timeout, TimeUnit unit) throws InsufficientFundsException, InterruptedException { long fixedDelay = getFixedDelayComponentNanos(timeout, unit); long randMod = getRandomDelayModulusNanos(timeout, unit); long stopTime = System.nanoTime() + unit.toNanos(timeout); while (true) { if (fromAcct.lock.tryLock()) { try { if (toAcct.lock.tryLock()) { try { if (fromAcct.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAcct.debit(amount); toAcct.credit(amount); return true; } } finally { toAcct.lock.unlock(); } } } finally { fromAcct.lock.unlock(); } } if (System.nanoTime() < stopTime) return false; NANOSECONDS.sleep(fixedDelay + rnd.nextLong() % randMod); } }

定時鎖:

索取鎖的時候可以設定1個超時時間,如果超過這個時間還沒索取到鎖,則不會繼續梗塞而是放棄此次任務,示例代碼以下:

public boolean trySendOnSharedLine(String message, long timeout, TimeUnit unit) throws InterruptedException { long nanosToLock = unit.toNanos(timeout) - estimatedNanosToSend(message); if (!lock.tryLock(nanosToLock, NANOSECONDS)) return false; try { return sendOnSharedLine(message); } finally { lock.unlock(); } }
還有可中斷鎖的獲得和非塊結構加鎖、讀寫鎖,加鎖一樣還有性能斟酌因素,和鎖的公平性,和如何選擇ReentrantLockSynchronized,這些將在下篇博客介紹。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 日韩欧美区 | 国产高清一二三区 | 91在线激情视频 | 91看片王| 国产天堂在线 | 国产欧美日| 91精品国产欧美一区二区成人 | 成午夜精品一区二区三区软件 | 日韩精品1区 | 久久久鲁 | 亚洲一级片 | 亚洲国产精品va在线看黑人动漫 | 国产一区二区免费在线 | 色片网站在线观看 | 欧美成人三区 | 欧美一区二区三区精品 | 九九香蕉视频 | 国产精品久久久久久久免费看 | 亚洲精品国产精品国自产观看浪潮 | 天天操天天av | 中文在线一区 | 成人精品久久 | 成人在线观看网站 | 毛片99 | 欧美com | 久久精品不卡 | 九九热精品在线视频 | 不卡的av在线播放 | 一区二区三区免费观看 | 天天干,夜夜操 | 亚洲一区二区国产 | 国产精品成人在线 | 亚洲一区二区视频 | 黄色一级大片在线免费看产 | 久久亚洲二区 | 久久国产精品成人免费观看的软件 | 亚洲欧洲成人av每日更新 | 国产激情在线视频 | 99精品视频一区二区三区 | 亚洲精品久久久久久久久久久久久 | 黄色电影免费看 |