java 線程synchronized 線程同步

1、多線程的同步:
1.1、同步機制:

在多線程中,可能有多個線程試圖訪問一個有限的資源,必須預防這種情況的發生。所以引入了同步機制:在線程使用一個資源時爲其加鎖,這樣其他的線程便不能訪問那個資源了,直到解鎖後纔可以訪問。

1.2、共享成員變量的例子:
成員變量與局部變量:

成員變量:

如果一個變量是成員變量,那麼多個線程對同一個對象的成員變量進行操作,這多個線程是共享一個成員變量的。

局部變量:

如果一個變量是局部變量,那麼多個線程對同一個對象進行操作,每個線程都會有一個該局部變量的拷貝。他們之間的局部變量互不影響。

下面舉例說明:

實現了Runnable的線程類:













在main方法中用兩個線程操作同一個對象:













這裏如果把i變成成員變量,則輸出100個數字。

1.3、共享資源導致的讀取錯誤

下面舉個例子,兩個線程共用一個Number對象,通過Number類的getNumber方法獲取數據,讀取數據並改寫時,發現了重複讀操作:

首先創建一個Number類:





















線程類,在線程類中的私有屬性包含了Number類的引用:

















在main函數中創建兩個線程類,包含了同一個Number類實例的引用:











這樣,當第一個線程讀取Number中的number變量時先保存下來再休眠0.1秒,然後第二個線程再讀取number變量並保存,此時兩個線程保存了同樣的數字,在修改時,也就導致修改了同一個數字兩次。

2、同步機制的實現:
2.1、使用synchronized關鍵字創建synchronized方法:

使用synchronized關鍵字,該關鍵字修飾的方法叫做同步方法。

Java中每個對象都有一個鎖或者稱爲監視器,當訪問某個對象的synchronized方法時,表示將該對象上鎖,而不僅僅是爲該方法上鎖。

這樣如果一個對象的synchronized方法被某個線程執行時,其他線程無法訪問該對象的任何synchronized方法(但是可以調用其他非synchronized的方法)。直至該synchronized方法執行完。

靜態的synchronized方法調用情況:

當調用一個對象的靜態synchronized方法時,它鎖定的並不是synchronized方法所在的對象,而是synchronized方法所在對象對應的Class對象。這樣,其他線程就不能調用該類的其他靜態synchronized方法了,但是可以調用非靜態的synchronized方法。

結論:執行靜態synchronized方法鎖方法所在對象,執行非靜態synchronized方法鎖方法所在對象對應的Class對象。

下面是多線程調用靜態的方法的例子,由於鎖定了方法所在對象對應的Class對象,其他線程無法調用該方法所在對象其他的靜態synchronized方法:





    

    

    






















main方法中兩個線程分別調用同一個對象的兩個static synchronized方法:













一次只能調用一個靜態方法,直到執行完成。

2.2、使用synchronized創建同步代碼塊:

通過使用synchronized同步代碼塊,鎖定一個對象,該對象作爲可執行的標誌從而達到同步的效果:

































如果想要使用synchronized同步代碼塊達到和使用synchronized方法同樣的效果,可以鎖定this引用:



2.3、synchronized方法和synchronized同步代碼塊的區別:

synchronized同步代碼塊只是鎖定了該代碼塊,代碼塊外面的代碼還是可以被訪問的。

synchronized方法是粗粒度的併發控制,某一個時刻只能有一個線程執行該synchronized方法。

synchronized同步代碼塊是細粒度的併發控制,只會將塊中的代碼同步,代碼塊之外的代碼可以被其他線程同時訪問。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章