類有一個特性叫封裝,若是一個類,全部的field都是private的,並且沒有任何的method,那麼這個類就像是四面圍牆+天羅地網,沒有門。看起來就是一個封閉的箱子,外面的進不來,裏面的出不去,通常來講,這樣的類是沒用的。多線程
synchronized(obj){ // some code... }
這個用法就是使用了obj的鎖,來鎖定一個代碼塊。併發
1 publicsynchronizedvoid aMethod(){ 2 // some code... 3 }
這個時候它使用的是當前實例this的鎖,至關於下面的模式:性能
publicvoid aMethod(){ synchronized(this){ // some code... } }
1 class SyncData { 2 public void do1() { 3 synchronized(this) { 4 for (int i=0; i < 4; i++) { 5 System.out.println(Thread.currentThread().getName() + "-do1-" + i); 6 try{ 7 Thread.sleep(1000); 8 }catch(InterruptedException e) { 9 e.printStackTrace(); 10 } 11 } 12 } 13 14 } 15 16 public void do2() { 17 synchronized(this) { 18 for (int i=0; i < 4; i++) { 19 System.out.println(Thread.currentThread().getName() + "-do2-" + i); 20 try{ 21 Thread.sleep(1000); 22 }catch(InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } 26 } 27 } 28 }
建立1個SyncData的實例,開啓2個線程,一個線程調用實例的do1方法,另外一個線程調用實例的do2方法,你會看到他們之間是互斥的——即便2個線程訪問的是實例的不一樣的方法,依然不能同時訪問。由於決定是否能夠同時訪問的再也不是門,而是鎖。只要使用的是相同的對象鎖,就會互斥訪問。this
1 class SyncData { 2 private Object lock = new byte[0]; 3 4 public void do1() { 5 synchronized(lock) { 6 for (int i=0; i < 4; i++) { 7 System.out.println(Thread.currentThread().getName() + "-do1-" + i); 8 try{ 9 Thread.sleep(1000); 10 }catch(InterruptedException e) { 11 e.printStackTrace(); 12 } 13 } 14 } 15 } 16 }
思考下面的代碼是否能起到互斥訪問的做用:spa
1 class SyncData { 2 public void do1() { 3 Object lock = new byte[0]; 4 synchronized(lock) { 5 for (int i=0; i < 4; i++) { 6 System.out.println(Thread.currentThread().getName() + "-do1-" + i); 7 try{ 8 Thread.sleep(1000); 9 }catch(InterruptedException e) { 10 e.printStackTrace(); 11 } 12 } 13 } 14 } 15 }
這個是不能起到互斥做用的,由於每一次調用,局部變量lock都是不一樣的實例。也就是說,synchronized使用的鎖老是變化的。因此咱們再補充一點:只有使用相同的對象鎖,才能互斥訪問。因此識別所使用的鎖,是很重要的。.net
1 class SyncData { 2 public void do1() { 3 synchronized(this) { 4 for (int i=0; i < 4; i++) { 5 System.out.println(Thread.currentThread().getName() + "-do1-" + i); 6 try{ 7 Thread.sleep(1000); 8 }catch(InterruptedException e) { 9 e.printStackTrace(); 10 } 11 } 12 } 13 14 } 15 }
建立2個實例,分別交給2個線程中的1個去訪問,能互斥嗎?線程
class SyncData { public void do1() { synchronized(this.getClass()) { for (int i=0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + "-do1-" + i); try{ Thread.sleep(1000); }catch(InterruptedException e) { e.printStackTrace(); } } } } }
能夠互斥,無論一個類有多少個實例,它們調用getClass()返回的結果都是同一個實例。設計