线程_内部锁和同步
為什么80%的碼農都做不了架構師?>>> ??
內部鎖和同步
同步是使用被叫做內部鎖或者監控鎖(intrinsiclock or monitor lock.)的內部實體來實現的。(API文檔里面經常簡稱做monitor)內部鎖在同步的兩個方面都扮演了重要的角色:強制對一個對象狀態的獨占性訪問,建立“happens-before”關系,happens-before關系對可見性很重要。
每個對象都有一個與它相關的內部鎖。通常,一個線程需要對一個對象的域進行獨占性訪問或者一致性訪問的時候,這個線程就需要在訪問前去獲得這個對象 的內部鎖,然后在做完相關操作后釋放鎖。可以說一個線程在它請求和釋放鎖的這段時間擁有這個內部鎖。只要一個線程擁有一個對象的內部鎖,其他的對象就不能 再擁有它,其他對象在嘗試獲得時會被阻塞。
當一個線程釋放一個內部鎖的時候,這個釋放行為和后續對這個鎖的獲得行為就建立了“happens-before”關系。
同步方法中的鎖
當一個線程調用一個同步方法的時候,它會自動取請求這個方法的對象所擁有的鎖,方法return的時候自動釋放。即便方法是因為一個未捕獲異常而返回的鎖依然會被釋放。
你或許會疑惑一個靜態的同步方法被調用會發生什么,因為static的方法是跟類相關的而不是跟實例相關。這種情況下,線程會去嘗試獲得與這個類相關的Class對象的內部鎖。所以對類的靜態域的訪問和對實例的訪問是受控于不同的鎖。
同步塊
另一種創建同步代碼的方式是使用同步塊,與使用同步方法不同,使用同步塊時必須指定提供內部鎖的對象。
public void addName(String name){
??? synchronized(this) {
??????? lastName = name;
??????? nameCount++;
??? }
??? nameList.add(name);
}
?
在這個例子中,addName方法需要去同步對lastName和nameCount的改變,但是也需要防止對其他對象的方法的同步調用。(對其他 對象的方法在同步塊中調用可能產生生命性問題。)如果不用同步塊的話,那就需要為只為了調用nameList.add(name)而創建一個單獨的,非同 步的方法。
同步塊對于提高非常精細的同步的并發性也是很有用的。假設,類MsLunch有兩個字段,c1和c2,他們不會被同時使用。對于兩個字段的所有單獨 的更改操作都需要被同步,但是沒有理由組織對c1的更改操作和對c2的更改操作交錯執行,這樣反而因為多余的阻塞而降低了并發。我們可以創建兩個單獨的對 象來提供不同的鎖:
public?class?MsLunch?{ ????private?long?c1?=?0; ????private?long?c2?=?0; ????private?Object?lock1?=?new?Object(); ????private?Object?lock2?=?new?Object(); ?????public?void?inc1()?{ ????????synchronized(lock1)?{ ????????????c1++; ????????} ????} ?
????public?void?inc2()?{ ????????synchronized(lock2)?{ ????????????c2++; ????????} ????} }
?
使用這種方式需要特別小心,你必須絕對的肯定相關的方法可以被交錯的調用。
折返同步
回想前面所說的一個線程不能獲得另外一個線程已經擁有的鎖。但是一個線程可以獲得它自己已經擁有的鎖。允許一個線程不只一次的獲得它自己已經擁有的 鎖,這樣能夠保證折返同步。這描述了這樣一個場景,一個同步的代碼,直接或者間接的調用了另外一個同步方法,而這兩個同步方法擁有同一個鎖。如果沒有折返 同步的話,同步代碼需要做更多額外的工作來保證它不被自己的鎖阻塞。
轉載于:https://my.oschina.net/ZGang/blog/375287
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: 网络中间设备路在何方
- 下一篇: UncaughtExceptionHan