二 多執行緒併發訪問

2021-09-11 08:57:42 字數 3224 閱讀 8504

非執行緒安全是多個執行緒對同乙個物件中的例項變數進行併發訪問時發生的,取到的資料其實是被更改過的。而執行緒安全就是以獲得的例項變數的值是經過同步處理的

1.synchronized同步方法

只有共享資源的讀寫訪問需要同步化

1.出現異常,鎖會自動釋放

2.同步不具有繼承性

(1) 方法內的變數執行緒安全
理解:區域性變數(方法內部的私有變數)是執行緒安全的,程式在new object() 時會為類中的屬性成員變數開闢空間,在方法區開闢乙個記憶體空間並且只存乙份是共用的**段(引用在棧區,變數在堆區);而方法中的私有變數只有在呼叫時在對應呼叫執行緒中開闢出記憶體空間,有幾個執行緒呼叫則每個執行緒都會在自己的執行緒空間的棧中為區域性變數申請幾個引用,同時在堆中為變數申請對應的空間 (即多執行緒在呼叫時只會處理自己執行緒內的方法的私有變數)

(2) 例項變數非執行緒安全

多個執行緒共同訪問同個物件中的例項變數,則有可能出現非執行緒安全問題。

(3) 多個物件多個鎖

關鍵字 synchronized取得的鎖都是物件鎖,哪個執行緒先執行帶 synchronized關鍵字的方法,哪個執行緒就持有該方法所屬物件的鎖lock,如果多個執行緒訪問多個物件,則jvm會建立多個鎖,執行結果是非同步的。

如果在靜態方法上加synchronized關鍵字,表示鎖定類級別的鎖,獨佔class類,這時候多個執行緒訪問的是相同的鎖。

當a執行緒呼叫object物件synchronized關鍵字修飾的x方法時,a執行緒就獲得了x方法所在物件的鎖,其他執行緒必須等a執行緒執行完畢才可以呼叫ⅹ方法,而b執行緒如果呼叫object物件synchronized關鍵字修飾的非ⅹ方法時 (可以呼叫object物件的非synchronized修飾的方法),必須等a執行緒將ⅹ方法執行完,也就是釋放物件鎖後才可以呼叫。

(4) synchronized鎖重入

可重入鎖是:自己可以再次獲取自己的內部鎖。使用 synchronized時,當乙個執行緒得到乙個物件鎖後,再次請求此物件鎖時可以再次得到。即synchronized方法/塊的內部呼叫本類的其他 synchronized方法/塊時,是可以得到鎖的。

public class run 

}public class threadiv extends thread

}public class service

public synchronized void serviceb()

}

執行緒a獲得了某個物件的鎖,此時這個物件鎖還沒有釋放,當其再次想要獲取這個物件的鎖的時候還是可以獲取的(支援父子類繼承),如果不可鎖重入的話,就會造成死鎖。

2.synchronized同步語句塊

(1) 同步方法和同步**塊比較

同步方法弊端:當業務邏輯複雜時,同步方法影響執行效能

當乙個執行緒訪問object中synchronized修飾的方法或synchronized(this) 同步**塊時,其他執行緒對同乙個 object中synchronized修飾的不同方法或其他 synchronized (this))同步**塊的訪問將被阻塞。synchronized(this)**塊是鎖定的當前物件

注意:

同步**塊(synchronized(this))放在非同步方法(無synchronized修飾)中進行宣告,並不能保證執行緒呼叫的方法體同步執行(同步**塊中執行是同步的)

(2) 靜態同步方法和synchronized(class)比較

synchronized關鍵字加到static靜態方法上是給class類上鎖,而 synchronized關鍵字加到非static靜態方法上是物件上鎖,class鎖可以對類的所有物件例項起作用。

同步 synchronized(class)**塊的作用和synchronized static方法的作用一樣。

3.多執行緒死鎖

不同的執行緒都在等待根本不可能被釋放的鎖,從而導致所有的任務都無法繼續進行;在設計程式時要避免雙方互相持有對方鎖的情況,只要互相等待對方釋放鎖就可能出現死鎖。

例如:

① synchronize巢狀的**結構來形成死鎖

② synchronize方法**現無限迴圈

public synchronized void threadrun() 

}

4.volatile關鍵字

(1) 解決死迴圈問題

public class threadv implements runnable 

@override

public void run()

system.out.println("多執行緒呼叫結束!");

}}public class runmain

}

執行結果:程式進入死迴圈(迴圈輸出 「thread is running」)

原因:

在啟動執行緒時,變數 private boolean isrunning=true存在於公共堆疊及執行緒的私有堆疊中。為了執行的效率,執行緒只在私有堆疊中取得 isrunning的值是true。而** threadv.setrunning(false)被執行時,更新的卻是公共堆疊中的 isrunning變數值 false,所以一直就是死迴圈的狀態。

解決:通過使用關鍵字 volatile強制從公共堆疊中取得變數的值,而不是從執行緒私有資料棧中取得變數的值。

(2) volatile和synchronized比較
① volatile是執行緒同步的輕量級實現,只能修飾於變數;而 synchronized可以修飾方法和**塊。

② 多執行緒訪問 volatile不會發生阻塞,而 synchronized會出現阻塞。

③ volatile能保證資料的可見性,但不能保證原子性;而 synchronized可以保證原子性,也可以間接保證可見性(它會將私有記憶體和公共記憶體中的資料做同步)

④ volatile解決的是變數在多個執行緒之間的可見性;而 synchronized關鍵字解決的是多個執行緒之間訪問資源的同步性。

《多執行緒併發》(二)

1.執行緒通訊 概念 執行緒通訊的目標是使執行緒間能夠互相傳送訊號。另一方面,執行緒通訊使執行緒能夠等待其他執行緒的訊號,多個執行緒在處理同乙個資源,並且任務不同時,需要執行緒通訊來幫助解決執行緒之間對同乙個變數的使用或操作。就是多個執行緒在操作同乙份資料時,避免對同一共享變數的爭奪。於是我們引出了...

spring mvc 多執行緒併發訪問總結

spring中的bean預設是單例的,這樣如果我們寫的bean是有狀態的就會產生執行緒安全問題,有狀態的bean就是指類中存在例項變數,伺服器會為每個請求開乙個執行緒,這樣當乙個執行緒修改了例項變數,另乙個執行緒訪問的變數就是被修改過的,這就是執行緒不安全的。我們以controller為例,下面是測...

多執行緒併發

多執行緒併發主要有3個方面 1 同步器 主要有synchronized,reentrantlock 訊號量,門栓 countdownlatch 障柵 cyclicbarrier 交換器。2 同步容器 主要包括 對映 集 佇列 對映 concurrenthashmap,concurrentskipli...