在介紹Synchrinized以前,咱們先來了解一下併發的相關概念。編程
併發: 同一時間段,多個任務都在執行 (單位時間內不必定同時執行);在同一時刻只會有一條指令執行,可是多個指令被快速輪換執行,這個切換的時間很是短以致於咱們不用去考慮它,這就是併發的基本含義。安全
而多線程正是咱們能夠完成併發的很重要的執行手段。如今的系統動不動就要求百萬級的併發量,而多線程併發編程正是開發高併發系統的基礎,利用好多線程的特性能夠大大的提升咱們的系統運行的效率。並且當今正值多核CPU時代,多線程也能夠提升咱們CPU的利用效率,最大化的利用咱們現有的資源。bash
上文說了多線程這麼多的好處,那麼它有什麼缺點呢?多線程
咱們在多線程的環境下,系統的執行順序並非由咱們控制的,執行的線程就可能隨時切換到其餘線程中執行。這就可能會形成一些安全性的問題。 好比小A小B兩我的同時在搶票(僅剩一張),小A買票的線程先執行,判斷 num 是否大於0(如今 num =1),而後 num--。執行完這個操做以後,小B線程也開始執行,也開始判斷 num 是否大於0,由於小A更新的num還沒有更新到主存中,小B的工做空間的 num 值仍是大於1,因此也執行 num--。併發
這個時候問題就出現了,只有一張票,作了兩次 num--,最後num的值爲-1系統就出現了錯誤。那麼如何防止這種現象出現呢?這裏咱們就引入了 Synchronzied。高併發
Synchronized 關鍵字解決的是多個線程之間訪問資源的同步性,Synchronized 關鍵字能夠保證被它修飾的方法或者代碼塊在任意時刻只能有一個線程執行。spa
還用剛纔的買票問題舉例,下面是代碼線程
while (true) {
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
}
}
}
複製代碼
此次咱們使用了 Synchronized 來對整個 if 語句進行修飾,就保證了if語句的原子性,只有當整個 if 語句的代碼執行完畢的時候,纔會釋放鎖,咱們也就很容易的解決了買票的問題。code
下面咱們來介紹一下 Synchronzied 的主要使用方式對象
synchronized 關鍵字最主要的三種使用方式:
* 修飾實例方法: 做用於當前對象實例加鎖,進入同步代碼前要得到當前對象實例的鎖
* 修飾靜態方法: 也就是給當前類加鎖,會做用於類的全部對象實例,由於靜態成員不屬於任何一個實例對象,是類成員( static代表這是該類的一個靜態資源,無論new了多少個對象,只有一份)。因此若是一個線程A調用一個實例對象的非靜態 synchronized 方法,而線程B須要調用這個實例對象所屬類的靜態 synchronized 方法,是容許的,不會發生互斥現象,由於訪問靜態 synchronized 方法佔用的鎖是當前類的鎖,而訪問非靜態 synchronized 方法佔用的鎖是當前實例對象鎖。
* 修飾代碼塊: 指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要得到給定對象的鎖。
這些就是今天介紹 Synchronized 的所有內容,從此我也會持續在個人專欄中更新更多有價值的內容,歡迎關注。