Java同步(Synchronization)

來源:互聯網
上載者:User

標籤:對象   html   oid   必須   hid   變數   順序   產生   出現   

前言

線程間的通訊主要通過共用對欄位的訪問和對象引用欄位的引用,可能會產生兩種錯誤,線程幹擾和記憶體一致性錯誤。Java的同步就是防止這些錯誤,但當多個線程訪問同一資源會導致線程執行緩慢,甚至暫停執行。

線程幹擾(Thread Interference)

例子

class Counter {    private int c = 0;    public void increment() {        c++;    }    public void decrement() {        c--;    }    public int value() {        return c;    }}
View Code

如果現在有兩個線程,線程A執行increment,線程B執行decrement,它們都使用了相同的變數c,這時會發生幹擾。即便是執行非常簡單的語句,但簡單語句也可以轉化為Java虛擬機器的多個步驟,例如c++可以分解為三個步驟:

1、檢索c的當前值。

2、將檢索值加1。

3、將值儲存回c中。

PS:c—也可以分解為相同步驟,只是第二步是減1。

假如線程A和線程B幾乎同時調用,c的初始值為0,則它們交錯的步驟可能是以下順序:

線程A:檢索c。線程B:檢索c。線程A:增加檢索值;結果是1。線程B:減少檢索值;結果是-1。線程A:將結果儲存在c中; c現在是1。線程B:將結果儲存在c中; c現在是-1。

線程A的結果丟失了,被線程B覆蓋了。這種交錯只是一種可能性,也可能是B的結果丟失,也可能不會出錯。也就是因為順序是不可預測的,所以線程幹擾的錯誤可能難以發現和修複。

記憶體一致性錯誤

不同線程看到的記憶體中的同一份資料卻有不同的“視圖”,原因很複雜,作為程式員最需要做的是處理好“happens-before”的關係,避免問題。

同步方法

Java提供了兩種基本的同步方法:同步方法和同步語句。同步的行為是依賴鎖來構建的,每一個對象都有與之相關的固定鎖,想要獨佔訪問對象的線程必須先擷取對象的鎖(拿不到阻塞線程),完成後釋放鎖,同時與請求同一鎖的線程建立一個happens-before關係。

同步方法的作用:

1、當一個線程正在執行一個對象的同步方法時,所有其他調用該對象的同步方法的線程將被阻塞,直到第一個線程執行完成。

2、當一個同步方法退出後,會自動建立與後續調用的同步方法(相同對象)的一個happens-before關係,保證所有線程對對象狀態的修改可見。

注意:

1、在建構函式中使用synchronized關鍵字是語法錯誤。同步建構函式沒有意義,因為只有建立對象的線程在構建時才能訪問它。

2、如果一個對象對多個線程可見,則通過同步方法完成對該物件變數的所有讀取或寫入操作,不然還是會出現線程幹擾和記憶體一致性錯誤。

public class SynchronizedCounter {    private int c = 0;    public synchronized void increment() {        c++;    }    public synchronized void decrement() {        c--;    }    public synchronized int value() {        return c;    }}
View Code

同步語句

另一種建立同步代碼的方法,與同步方法不同,同步語句必須指定提供內部鎖的對象。同步語句有利於通過細粒度同步來提高並發性。

例如,假設類MsLunch具有兩個執行個體欄位c1和c2,它們從不一起使用(很重要的前提條件!)。這些欄位的所有更新都必須同步,但沒有理由阻止c1的更新與c2的更新交錯,這樣做會建立不必要的阻塞來降低並發性。我們不使用同步方法,而是建立兩個對象來提供鎖。

public class MsLunch {    private long c1 = 0;    private long c2 = 0;    private Object lock1 = new Object();    private Object lock2 = new Object();    public void inc1() {        synchronized(lock1) {            c1++;        }    }    public void inc2() {        synchronized(lock2) {            c2++;        }    }}
View Code

volatile關鍵字

原子操作:一個原子操作,要麼發生,要麼不發生。比如 c=0;(非long和double類型) 這個操作是執行了就會發生。再比如:c++;可分割成三個操作步驟,執行時可能會丟失某些步驟,就不是一個原子操作。非原子操作都會存線上程安全問題,同步方法和同步語句可以讓它變成一個原子操作。

volatile變數是一種稍弱的同步機制,所有聲明為volatile的變數(包括long和double),讀取和寫入都是原子的。

volatile變數特性:

1、當一個線程讀取一個volatile變數時,它看到總是最新的值。

2、原子動作不能交錯,使用volatile變數不用擔心線程幹擾。

PS:java.util.concurrent包下提供了一些原子類。

參考文獻

https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

Java同步(Synchronization)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.