1. 程式人生 > >Java鎖機制:Synchronized,Lock,Condition

Java鎖機制:Synchronized,Lock,Condition

1、synchronized

把程式碼塊宣告為synchronized,有兩個重要後果,通常是指該程式碼具有原子性(automicity)和可見性(visibility)。

原子性

原子性意味著某個時刻,只有一個執行緒能夠執行一段程式碼,這段程式碼通過一個monitor Object保護。從而防止多個執行緒在更新共享狀態時相互衝突。

可見性

可見性要對付記憶體快取和編譯器優化的各種反常行為。它必須確保釋放鎖之前對共享資料做出的更改對於隨後獲得該鎖的另一個執行緒是可見的。

作用:如果沒有同步機制提供這種可見性保證,執行緒看到的共享變數可能是修改前的值或不一致的值,這將引發許多嚴重問題。

原理:當物件獲取鎖時,它首先使自己的快取記憶體無效,這樣就可以保證直接從主記憶體中裝入變數。同樣,在物件釋放鎖之前,它會重新整理其快取記憶體 ,

強制使已做的任何更改都出現在主記憶體中。這樣,可以保證在同一個鎖上同步的兩個執行緒看到在synchronized塊內修改的變數的相同值。

一般來說,執行緒以某種不必讓其他執行緒立即可以看到的方式(不管這些執行緒在暫存器中、在處理器特定的快取中,還是通過指令重排或者其他編譯器優化),不受快取變數值的約束,但是如果開發人員使用了同步,那麼執行庫將確保某一執行緒對變數所做的更新先於對現有synchronized塊所進行的更新,當進入由同一監控器(lock)保護的另一個synchronized塊時,將立刻可以看到這些對變數所做的更新。

類似的規則也存在與volatile變數上————————volatile只保證可見性,不保證原子性

需要同步的場景

可見性同步的基本規則是在以下情況中必須同步:

1.讀取上一次可能是由另一個執行緒寫入的變數
2.寫入下一次可能由另一個執行緒讀取的變數

一致性同步:當修改多個相關值時,你想要其他執行緒原子地看到這組更改——要麼看到全部更改,要麼什麼也看不到。

這適用於相關資料項(如粒子的位置和速率)和元資料項(如連結串列中包含的資料值和列表自身中的資料項的鏈)

但在某些情況中,不必用同步來將資料從一個執行緒傳遞到另一個,因為JVM已經隱含地為您執行同步。這些情況包括:

1.由靜態初始化器(在靜態欄位上或static{}塊中的初始化器)
2.初始化資料時
3.訪問final欄位時
4.在建立執行緒之前建立物件時
5.執行緒可以看見它將要處理的物件

synchronized的限制

synchronized有一些功能上的限制:

1.它無法中斷一個正在等候獲得鎖的執行緒
2.無法通過投票得到鎖,如果不想等下去,也就沒法得到鎖
3.同步還要求鎖的釋放只能在與獲得鎖所在的堆疊幀相同的堆疊幀中進行,多數情況下,這沒問題(而且與異常處理互動的很好),但是,確實存在一些非塊結構的鎖更合適的情況

2.ReentrantLock

Java.util.concurrent.lock的Lock框架是鎖定的一個抽象,它允許把鎖定的實現作為Java類,而不是作為語言的特性來實現。
這為Lock的多種實現留下了空間,各種實現可能有不同的排程演算法、效能特性或者鎖定語義。
ReentrantLock類實現了Lock,它擁有與synchronized相同的併發性和記憶體語義,但是添加了類似投票、定時鎖等候和可中斷鎖等候的一些特性。
它還提供了在激烈爭用情況下更佳的效能。即,當許多執行緒都想訪問共享資源時,JVM可以花更少的時間來排程執行緒,把更多的時間用在執行執行緒上。
注意:用synchronized修飾的方法或者語句塊在程式碼執行完之後鎖自動釋放,而Lock類需要手動釋放,所以為了保證鎖最終被釋放(發生異常情況時),要把互斥區放在try內,釋放鎖放在finally內!

3.讀寫鎖ReadWriteLock

與互斥鎖相比,讀-寫鎖定允許對共享資料進行更高級別的併發訪問。雖然一次只有一個執行緒(writer執行緒)可以修改共享資料,但在許多情況下,
任何數量的執行緒可以同時讀取共享資料(reader執行緒)
從理論上講,與互斥鎖相比,讀-寫鎖所允許的併發效能增強將帶來更大的效能提高。
只有在多處理器上並且只在訪問模式適用於共享資料時,才能實現併發性增強。
————例如,某個最初用資料填充並且之後不經常對其進行修改的Collection,因為經常對其進行搜尋(比如搜尋某種目錄),所以這樣的Collection是使用讀-寫鎖定的理想候選者。

4.執行緒間通訊Condition

Condition可以替代傳統的執行緒間通訊,用await()替換wait(),用signal()替換notify(),用signalAll()替換notifyAll()。

為什麼方法名不直接叫wait()/notify()/notifyAll()?因為Object的這幾個方法是final的,不可重寫!

傳統執行緒的通訊方式,Condition都可以實現。
Condition是被繫結到Lock上的,要建立一個Lock的Condition必須用newCondition()方法。
Condition的強大在於它可以為多個執行緒間建立不同的Condition。

package test.concurrent;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
     final Lock lock = new ReentrantLock();  //鎖物件
     final Condition notFull = lock.newCondition(); //寫執行緒鎖
    final Condition notEmpty = lock.newCondition();//讀執行緒鎖
    final Object[] items = new Object[100];   //快取佇列
    int putptr;                                 //寫索引
    int takeptr;                            //讀索引
    int count;                              //佇列中資料數目
    //寫
    public void put(Object x)throws InterruptedException{
        lock.lock();    //鎖定
        try{
            //若佇列已滿,則將 寫執行緒 放入阻塞佇列
            while(count == items.length){
                notFull.await();
            }
            //寫入佇列,並更新寫索引
            items[putptr] = x;
            if(++putptr == items.length)putptr=0;
            ++count;
            //喚醒 讀執行緒
            notEmpty.signal();
        }finally{
            lock.unlock();//解除鎖定
        }
    }
    //讀
    public Object take() throws InterruptedException{
        lock.lock();    //鎖定
        try{
            //若佇列為空,則將 讀執行緒 放入阻塞佇列
            while(count == 0){
                notEmpty.await();
            }
            //讀取佇列,並更新讀索引
            Object x = items[takeptr];
            if(++takeptr == items.length)takeptr = 0;
            --count;
            //喚醒 寫執行緒
            notFull.signal();
            return x;
        }finally{
            lock.unlock();//解除鎖定
        }
    }
}  

其實就是java.util.concurrent.ArrayBlockingQueue

相關推薦

Java線程】機制synchronizedLockCondition轉載

留下 初始化 char 想要 interrupt 機制 運行 -m 特性 http://www.infoq.com/cn/articles/java-memory-model-5 深入理解Java內存模型(五)——鎖 http://www.ibm.com/develope

Java執行緒】機制synchronizedLockCondition

http://www.infoq.com/cn/articles/java-memory-model-5  深入理解Java記憶體模型(五)——鎖 http://www.ibm.com/developerworks/cn/java/j-jtp10264/  Java 理論與

Java機制SynchronizedLockCondition

1、synchronized 把程式碼塊宣告為synchronized,有兩個重要後果,通常是指該程式碼具有原子性(automicity)和可見性(visibility)。 原子性 原子性意味著某個時刻,只有一個執行緒能夠執行一段程式碼,這段程式碼通過

Java執行緒機制synchronizedLockCondition

原文:http://blog.csdn.net/vking_wang/article/details/9952063     1、synchronized   把程式碼塊宣告為 synchronized,有兩個重要後果,通常是指該程式碼具有

MySQL使用可重複讀作為預設隔離級別的原因(二)-》Innodb機制Next-Key Lock 淺談

資料庫使用鎖是為了支援更好的併發,提供資料的完整性和一致性。InnoDB是一個支援行鎖的儲存引擎,鎖的型別有:共享鎖(S)、排他鎖(X)、意向共享(IS)、意向排他(IX)。為了提供更好的併發,InnoDB提供了非鎖定讀:不需要等待訪問行上的鎖釋放,讀取行的一個快照。該方法是通過InnoDB的一個特

Innodb機制Next-Key Lock 淺談

root@localhost : test 10:56:10>create table t(a int,key idx_a(a))engine =innodb; Query OK, 0 rows affected (0.20 sec) root@localhost : test 10:56:13&

java機制LOCK的實現類

1.synchronized --把程式碼塊宣告為 synchronized,有兩個重要後果,通常是指該程式碼具有 原子性(atomicity)和 可見性(visibility)。1.1 原子性--原子性意味著個時刻,只有一個執行緒能夠執行一段程式碼,這段程式碼通過一個mo

淺談資料庫機制(只是本人的一些瞭解個人觀點)

首先:需要明確鎖的分類 鎖包括行級鎖、表級鎖、悲觀鎖、樂觀鎖 首先行級鎖:又叫排他鎖,多見於支援高併發的資料庫搜尋引擎中出現使用,如mysql中的innodb預設是行級鎖;在以下查詢中oracle中會自動應用行級鎖。釋放行級鎖時使用commit或者rollback釋放

JAVA機制-可重入,可中斷公平讀寫自旋

部落格引用處(以下內容在原有部落格基礎上進行補充或更改,謝謝這些大牛的部落格指導): JAVA鎖機制-可重入鎖,可中斷鎖,公平鎖,讀寫鎖,自旋鎖 在併發程式設計中,經常遇到多個執行緒訪問同一個 共享資源 ,這時候作為開發者必須考慮如何維護資料一致性,在java中synchronized

java機制的兩種實現synchronized 與ReentrantLock

java的多執行緒環境下併發是常見問題,這兩天看了鎖相關的問題,記錄下兩個簡單的用鎖實現等待/喚醒機制的demo。 1.synchronized方式實現等待/喚醒。 public class WaitAndNotify { private static boolean flag =

Java併發程式設計Synchronized底層優化(偏向、輕量級Java併發程式設計Synchronized底層優化(偏向、輕量級

轉自:https://www.cnblogs.com/paddix/p/5405678.html Java併發程式設計:Synchronized底層優化(偏向鎖、輕量級鎖)   Java併發程式設計系列: J

java synchronized java機制

java鎖synchronized 解決的問題:搶資源 關於鎖方法    鎖靜態方法鎖的鎖 class,鎖非靜態方法鎖的是類的例項  this  ,鎖方法相當於鎖程式碼塊,不阻塞其他非鎖部分程式碼塊或者方法的執行 1.靜態方法訪問靜態變數 &nb

Java 100-002Swing顯示視窗並在視窗中顯示文字

package java01; import java.awt.*; import javax.swing.*; /** * 我的java每天100行程式碼002 * Swing顯示視窗,並在視窗中輸出一串文字 * @author Administrator * */ p

Java併發程式設計Synchronized底層優化(偏向、輕量級

Java併發程式設計系列: 一、重量級鎖   上篇文章中向大家介紹了Synchronized的用法及其實現的原理。現在我們應該知道,Synchronized是通過物件內部的一個叫做監視器鎖(monitor)來實現的。但是監視器鎖本質又是依賴於底層的作業系統的Mutex Lock來實現的。而

面試分享螞蟻三面面經(Java機制+JVM+執行緒池+事務+中介軟體)

一面 1、HashMap底層原理?HashTable和ConcurrentHashMap他們之間的相同點和不同點? 2、由上題提到鎖的問題 3、MySQL的表鎖&行鎖&樂觀鎖&悲觀鎖,各自的使用場景 4、Java執行緒鎖有哪些,各自的優劣勢 5、事務四大特

資料庫機制 很詳細的教程易懂

1) holdlock 對錶加共享鎖,且事物不完成,共享鎖不釋放。 2) tablock 對錶加共享鎖,只要statement不完成,共享鎖不釋放。 與holdlock區別,見下例: 例21 ---------------------------------------- T1:

Java RPC 程式設計Motan 實現示例叢集配置

在多個伺服器程序之間的通訊,目前使用的技術一般是 RPC(Remote Procedure Call Protocol,遠端過程呼叫協議)。 使用 RPC 可以訪問遠端主機的程序服務,不需要清楚底層網路通訊機制,只需要關注服務本身即可。RPC 是目前分散式開發技術中一種常用的技術,其

Java經典例項正則表示式找到匹配的文字

import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by Frank */ public class REMatch { public static void main(

Java 6-4別看了坑的就是你——活性失敗-volatile

執行緒A對某變數值的修改,可能沒有立即線上程B體現出來,稱為活性失敗。 注意下面這個例子,在PC和安卓上執行結果可能不一樣(安卓可能不需要volatile) 例子 public class VolatileTest extends Thread {

Java 6-2收放自如融匯貫通讓執行緒不再瘋癲——執行緒的阻塞和關閉

本節重點說說執行緒什麼時候會阻塞,如何關閉 1 讓出時間片 Thread.yield(); 通知並建議執行緒排程器,我已經做完了主要工作,時間片你可以分給別人了 即使呼叫了這個,還是可能沒有切換時間片,或者切換了,但是還是給了當前執行緒 Threa