天天看點

關于java中的 sychronized 同步方法 與 同步塊的了解

 首先,需要說明一點,也是最重要的一點,無論是同步方法 還是 同步塊 都是隻針對同一個對象的多線程而言的,隻有同一個對象産生的多線程,才會考慮到 同步方法 或者是 同步塊,如果定義多個執行個體的同步,可以考慮使用mutex,建立類似于c++整個服務全局鎖,或者建立一個全局單例類,在其内定義全局鎖。比如以下的代碼片段定義線程同步無任何意義:

public class Test1 implements Runnable {

    public void run() {

        synchronized(this) {

            try {

                System.out.println(System.currentTimeMillis());

                Thread.sleep(2000);

                System.out.println(System.currentTimeMillis());

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

    public static void main(String[] args) {

        for(int i=0;i<10;i++) {

            new Thread(new Test1()).start(); // 關鍵,如果将 new Test1拿到外面,那麼同步方法才有意義,如下:

    //public static void main(String[] args) {

     //    Test1 test=new Test1();

     //    for(int i=0;i<10;i++) {

     //        new Thread(test).start();

        }

    }

}

因為java或者C#中的線程同步與多線程的概念,隻是在單個對象下 這一範圍内的,也就是說:單個對象下的 多線程同步 或者 死鎖。如果有下面的需求:

1,該類隻允許在同一時刻執行個體化(new)一次;----考慮單例模式

2,或者隻允許在同一時刻僅可存活一個對于資料庫的修改 或 删除操作;--考慮單例模式 或者 資料庫内的事務鎖概念。

-----------------------------------------------------

下面我們着重介紹java中的 Sychronized的用法,具體為:同步方法 與 同步塊

synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。

  1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:

  public synchronized void accessVal(int newVal);

  synchronized 方法控制對類成員變量的通路:每個類執行個體對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類執行個體的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法傳回時才将鎖釋放,此後被阻塞的線程方能獲得該鎖,重新進入可執行狀态。這種機制確定了同一時刻對于每一個類執行個體,其所有聲明為 synchronized 的成員函數中至多隻有一個處于可執行狀态(因為至多隻有一個能夠獲得該類執行個體對應的鎖),進而有效避免了類成員變量的通路沖突(隻要所有可能通路類成員變量的方法均被聲明為 synchronized)。

  在 Java 中,不光是類執行個體,每一個類也對應一把鎖,這樣我們也可将類的靜态成員函數聲明為 synchronized ,以控制其對類的靜态成員變量的通路。

  synchronized 方法的缺陷:若将一個大的方法聲明為synchronized 将會大大影響效率,典型地,若将線程類的方法 run() 聲明為 synchronized ,由于線上程的整個生命期内它一直在運作,是以将導緻它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過将通路類成員變量的代碼放到專門的方法中,将其聲明為 synchronized ,并在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。

  2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。文法如下:

  synchronized(syncObject) {

  //允許通路控制的代碼

  }

   synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類執行個體或類)的鎖方能執行,具體機制同前所述。由于可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。

  對synchronized(this)的一些了解

  一、當兩個并發線程通路同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間内隻能有一個線程得到執行。另一個線程必須等待目前線程執行完這個代碼塊以後才能執行該代碼塊。

  二、然而,當一個線程通路object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以通路該object中的非synchronized(this)同步代碼塊。

  三、尤其關鍵的是,當一個線程通路object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的通路将被阻塞。

  四、第三個例子同樣适用其它同步代碼塊。也就是說,當一個線程通路object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的通路都被暫時阻塞。

  五、以上規則對其它對象鎖同樣适用

------------------------------------------------------------------------

網上還有很多關于java中的Sychronized的個人了解與總結,可以忘記的時候看看,但是上面的東東是核心,切記。

此外最關鍵的,線程同步會耗費很多性能,是以如無必要,盡量少用線程同步,如果使用最好使用同步塊而不要使用同步方法。

用同步塊.. 同步方法就是在方法傳回類型後面加上synchronized, 比如:
public void synchronized add(){...}
同步塊就是直接寫:synchronized (這裡寫需要同步的對象){...}