synchronized基本使用以及原理

1. 場景

      在併發編程中存在線程安全問題,主要緣由有:存在共享數據,多線程共同操做共享數據。關鍵字synchronized能夠保證在同一時刻,只有一個線程能夠執行某個方法或某個代碼塊,同時synchronized能夠保證一個線程的可見性java

2. 概念

利用鎖的機制來實現同步的(解決數據點不一致性 JMM)編程

  • 鎖機制有以下兩種特性
  1. 互斥性
    在同一時間只容許一個線程持有某個對象鎖,經過這種特性來實現多線程中的協調機制,這樣在同一時間只有一個線程對所需同步的代碼塊(複合操做)進行訪問。互斥性也稱爲操做的原子性
  2. 可見性
    必須確保在鎖被釋放以前,對共享變量所作的修改,對於隨後得到該鎖的另外一個線程是可見的(即在得到鎖時應得到最新共享變量的值),不然另外一個線程多是在本地緩存的某個副本上繼續操做從而引發不一致。

3. synchronized的用法

  • 同步方法(分普通方法和靜態方法)
    用法:只須要在方法上面添加synchronized關鍵字便可。
    同步普通方法:只能做用在單例上面,若是不是單例,同步方法鎖將失效。
    同步靜態方法:無論你有多少個類實例,同時只有一個線程能獲取鎖進入這個方法。
  • 同步對象實例
private static int m = 0;
 private Object obj = new Object();

 public void test1() {
     try {
         synchronized (obj) {
             TimeUnit.MINUTES.sleep(2);
             m++;
         }
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
 }
  • 同步類

鎖效果與同步靜態方法同樣,都是類級別的鎖,同時只有一個線程能訪問帶有同步類鎖的方法。緩存

public class synchronizedDemo {
    private static int m = 0;
    public void test2() {
        try {
            synchronized (synchronizedDemo.class) {
                TimeUnit.MINUTES.sleep(2);
                m++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 同步this實例

與同步塊的用法一致,表示鎖住整個當前對象實例,只有獲取到這個實例的鎖才能進入這個方法。安全

private static int m = 0;
    public void test2() {
        try {
            synchronized (this) {
                TimeUnit.MINUTES.sleep(2);
                m++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

4. synchronized底層語義原理

可經過工具jconsole和jstack去觀察synchronized的底層以及線程狀況。多線程

  • 方法鎖:

方法鎖就是由關鍵字ACC_SYNCHRONIZED實現是否互斥方法,併發

  • 對象鎖:

monitor:在jvm規範中每一個對象和類在邏輯上都是和一個監視器(monitor)相關聯的,爲了實現監視器的排他性監視能力,JVM爲每個對象和類都關聯一個鎖,鎖住了一個對象,這就是得到對象相關聯的監視器。
實現原理:某一個線程佔有這個對象的時候,首先monitor的計數器是否是0,若是是0表示尚未線程佔有這個時候線程佔有這個對象,而且對這個對象的monitor+1;若是不爲0表示這個對象已經被其餘線程佔有,這個線程等待。當線程釋放佔有權的時候monitor-1。
注:同一個線程能夠對同一個對象屢次加鎖,+1,+1,重入鎖jvm

相關文章
相關標籤/搜索