看到網上不少資料都講解synchronized的用法詳解,確實有不少的知識點,但初學者可能看的比較頭暈,這裏淺談下很重要的synchronized修飾普通方法和修飾靜態方法,也是在實際開發中用的比較多的。java
這裏先說synchronized修飾普通方法,修飾代碼塊和修飾靜態方法的最大特色:安全
修飾普通方法,修飾代碼塊:只針對調用它的對象起做用。this
修飾靜態方法:針對該類的全部對象都起做用。線程
直接上代碼:code
public class SyncTest { public void test1(){ synchronized (this){ for (int i = 0; i < 10; i++) { log.info("test1 - {}",i); } } } public synchronized void test2(){ for (int i = 0; i < 10; i++) { log.info("test2 - {}",i); } } public static void main(String[] args) { SyncTest syncTest1 = new SyncTest(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() ->{ syncTest1.test1(); }); executorService.execute(() ->{ syncTest1.test1(); }); } }
輸出結果:對象
能夠看出,兩個線程很好的保持了同步,達到了線程安全的效果,blog
出現這個的緣由是:在test1方法中,咱們使用同一個對象調用它,因此每一個線程都要依次得到該對象的鎖才能執行,這裏注意的是,起做用的是該對象(同一個),下面調用test2方法結果也一致,由於執行代碼都在synchronized裏被修飾了。開發
可是若是咱們新增長一個對象,分別調用本身的test1方法,以下:同步
SyncTest syncTest1 = new SyncTest(); SyncTest syncTest2 = new SyncTest(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() ->{ syncTest1.test2(); }); executorService.execute(() ->{ syncTest2.test2(); });
結果:
class
能夠看到,結果是線程不一樣步的,這是由於用synchronized修飾的只對當前對象起做用,而對其餘對象的synchronized所針對的對象是不干擾的。
下面來看調用靜態方法會出現什麼結果:
public class SyncTest { public void test1(){ synchronized (this){ for (int i = 0; i < 10; i++) { log.info("test1 - {}",i); } } } public synchronized static void test2(){ //改成靜態方法 for (int i = 0; i < 10; i++) { log.info("test2 - {}",i); } } public static void main(String[] args) { SyncTest syncTest1 = new SyncTest(); SyncTest syncTest2 = new SyncTest(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() ->{ syncTest1.test2(); }); executorService.execute(() ->{ syncTest2.test2(); }); } }
咱們將test2方法改成靜態方法,也是建立兩個對象,調用本身的test2方法,結果以下:
能夠看到,線程也是同步的,這是由於synchronized修飾靜態方法(修飾類),起做用的對象是屬於整個類的,就是說只要是該類的對象在調用該類被synchronized修飾的方法時都要保持線程同步。
若是有錯誤的地方,請歡迎指正!