java之同步鎖---synchronized


1.背景

  前幾天線上項目出現一個問題,由於並發問題,導致服務器集群中的部分服務器中的數據沒有更新。經過review代碼,發現沒有進行數據的同步操作。最后使用synchronize解決了問題。解決問題后,在空余時間對synchronized的應用進行了研究。

2.synchronized介紹

synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種: 
1. 修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象; 
2. 修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象; 
3. 修改一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象; 
4. 修改一個類,其作用的范圍是synchronized后面括號括起來的部分,作用主的對象是這個類的所有對象。

3. 示例

3.1 synchronized修飾代碼塊

如果多個線程訪問的是同一個實例對象,則會出現等待,如果多個線程訪問的都是不同的實例對象,則不會出現等待

3.1.1 synchronized(this)

代碼如下:

 

 
         
public class SyncBlock implements Runnable{
    private static Integer count; public SyncBlock() { // TODO Auto-generated constructor stub count = 0; } public int getCount(){ return count; } @Override public void run() { // TODO Auto-generated method stub System.out.println("當前執行的程序:"+Thread.currentThread().getName()); synchronized(this) { for (int i = 0; i < 5; i++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args){ SyncBlock syncBlock = new SyncBlock(); Thread th1 = new Thread(syncBlock,"第一集團軍"); Thread th2 = new Thread(syncBlock,"第二集團軍"); th1.start(); th2.start(); } }
 

 

執行結果如下:


通過執行結果可以看出,同步鎖機制生效。synchronized(this)使得兩個線程同步等待。在main函數中增加三行代碼
 
public static void main(String[] args){
		SyncBlock syncBlock = new SyncBlock();
		SyncBlock syncBlock3 = new SyncBlock();
		Thread th1 = new Thread(syncBlock,"第一集團軍");
		Thread th2 = new Thread(syncBlock,"第二集團軍");
		Thread th3 = new Thread(syncBlock3,"第三集團軍");
		th1.start();
		th2.start();
		th3.start();
	}

執行結果如下:

通過執行結果可以看出,線程1和線程2之間出現了等待,線程1執行完之后執行線程2,而線程3與線程1和2之間沒有等待。這是因為線程1和線程2是監視的同一個SyncBlock對象syncBlock,而線程3監視的是獨立的對象syncBlock3。也就是說,synchronized(this)對於線程3與線程1和2,鎖的是不同對象,所以彼此之間無法同步。

3.1.2 靜態變量synchronized(this.count)

鎖的對象是整型的實例對象count,如果count對象值是固定不變的,則所有線程之間都會等待,如果count是變化的,如count++,則所有線程之間都不會等待。因為count++的結果會改變count的對象引用,所以
synchronized(count)鎖定的是不同的實例對象,也就沒有起到鎖的作用。
修改上面的代碼如下:

 1     public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("當前執行的程序:"+Thread.currentThread().getName());
 4           synchronized(count) {
 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }
13               }
14     }

執行結果如下:

如果count的值不發生改變

 1 public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("當前執行的程序:"+Thread.currentThread().getName());
 4           synchronized(count) {
 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }
13               }
14     }

執行結果如下:由於count值不發生變化,count是對多有實例對象共享,所以所有線程多會出現等待。

3.1.3  synchronized(A.class)

       A.class表示類對象。每個類都對應着一個這樣的類對象,所有線程都會彼此間等待。

修改代碼如下:

 1 public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("當前執行的程序:"+Thread.currentThread().getName());
 4           synchronized(SyncBlock.class) {
 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }
13               }
14     }

執行結果如下:

3.2 synchronized非靜態方法

 1 synchronized public void run() {
 2         // TODO Auto-generated method stub
 3           System.out.println("當前執行的程序:"+Thread.currentThread().getName()); 5                  for (int i = 0; i < 5; i++) {
 6                     try {
 7                        System.out.println(Thread.currentThread().getName() + ":" + (count++));
 8                        Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                        e.printStackTrace();
11                     }
12                  }14     }

執行結果如下,與在方法在使用synchronized(this)相同。多個線程訪問的是同一個實例對象,則會出現等待,如果多個線程訪問的都是不同的實例對象,則不會出現等待

 3.4 synchronized靜態方法

    靜態方法屬於類方法,不屬於任一實例對象。為所有實例對象所共享。因此對於所有線程調用synchronized靜態方法,彼此之間會出現等待。與synchronized(A.clsss)類似。只是作用范圍不同。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM