Synchronized與Lock

1、線程安全問題

多線程訪問一個共享資源時,可能會致使運行結果不是預計的結果。數據庫

好比兩個線程要往數據庫中插入一條數據。安全

兩個線程先檢查數據庫中有沒有這個數據,都檢測到沒有,因而都插入一條數據。但實際上只須要一條數據。多線程

對共享資源操做時,纔會有線程安全問題。線程

2、解決方法

序列化訪問臨界資源。同一時刻,只有一個線程訪問臨界資源。也叫同步互斥訪問。code

synchronized和Lock對象

3、synchronized

做用是給共享資源加上互斥鎖。當一個線程訪問時,其餘線程等待訪問。接口

synchronized能夠鎖方法,也能夠鎖代碼塊。資源

synchronized的本質是鎖對象。同步

Java中,每個對象都有一個所標記monitor。多線程訪問某個對象時,線程只有得到了該對象的鎖,才能訪問。源碼

三種情形

1.一個線程訪問一個對象的synchronized方法時,另外一個線程不能訪問該對象的synchronized方法,可是能夠訪問非synchronized方法。

2.一個線程訪問一個對象object1的synchronized方法時,另外一個線程能夠訪問對象object2的synchronized方法。object1和object2是同一個類型。 由於訪問的對象不同。

3.一個線程訪問一個對象的非靜態synchronized方法時,另外一個線程能夠訪問該對象的靜態synchronized方法。

由於靜態synchronized方法,佔領的鎖是類鎖,不是對象鎖。

彙編指令

synchronized編譯成兩條指令:monitorenter和monitorexit

monitorenter會讓對象的鎖計數加1。 monitorexist會讓對象的鎖計數減1。

拋出異常時,會釋放鎖對象,不會出現死鎖。

4、Lock

synchronized的缺陷

synchronized釋放鎖有兩種狀況:1.線程執行完,2.出現中斷異常。

若是synchronized中線程阻塞,其餘線程就要一直等待,很是影響效率。

因而就提供了功能更強大的Lock,來解決一些問題

Lock源碼

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

synchronized是Java的內置關鍵字。Lock是一個接口。

Lock中有這麼幾個方法:

lock(),unLock()

lock()用來獲取鎖,若是其餘線程已經獲取了鎖,那麼就等待。

和synchronized不同。Lock不會自動釋放鎖。因此必須手動釋放鎖,用unLock()。 通常放在try...catch()...finally()中。

tryLock()

tryLock有返回值,嘗試獲取鎖,若是獲取了鎖,就返回true,沒有獲取鎖,就返回false。也就是說,這個方法不會等待鎖。

通常用if(tryLock())..else...

lockInterruptibly()

使用lockInterruptibly()獲取鎖的狀況下,若是線程處於等待獲取鎖的狀態,調用interrupt能夠中斷線程,拋出異常。

ReentrantLock

實現了Lock的類。能夠實現可重入鎖。

ReadWriteLock和ReentrantReadWriteLock

是一個接口。定義了兩個方法。ReentrantReadWriteLock實現了該接口。

readLock()和writeLock()分別獲取讀鎖和寫鎖。

一個線程獲取了讀鎖,另外一個線程能夠得到該對象的讀鎖,不能得到該對象的寫鎖。

一個線程獲取了寫鎖,另外一個線程不能夠獲取該對象的讀寫鎖。

支持降級,寫鎖能夠降級爲讀鎖,可是讀鎖不能升級爲寫鎖。

5、Lock和Synchronized的選擇

1.synchronized是Java內置關鍵字,Lock是接口。

2.synchronized異常會自動釋放鎖,Lock要手動釋放。

3.synchronized沒法中斷等待獲取鎖的線程,Lock能夠。

4.synchronized沒法判斷線程是否獲取鎖,Lock能夠。

5.Lock可使用讀鎖,提升讀線程的效率。

6、鎖的類型

可重入鎖

一個鎖方法中調用另外一個鎖方法,線程不須要從新獲取鎖對象。

synchronized和Lock都是可重入鎖

公平鎖

等待獲取鎖的線程按請求順序獲取鎖對象。

synchronized是非公平鎖。 Lock默認是非公平鎖。可是能夠設置爲公平鎖。

ReentrantLock lock = new ReentrantLock(true);

可中斷鎖

能夠中斷等待鎖的線程。

synchronized是不可中斷鎖。Lock是可中斷鎖。

讀寫鎖

鎖分紅兩個,一個讀鎖,一個寫鎖。

synchronized沒有,ReadWriteLock是讀寫鎖。

相關文章
相關標籤/搜索