當對數據修改時,若是兩個線程同時去修改同一條數據,這樣產生的結果就不是咱們預期的結果。這時候就須要對修改操做進行加鎖,讓jvm裏同一時刻只能有一個線程可以執行修改方法。java
下面是一個未加鎖的修改方法: 多線程
public void update(Entry entry){ dao.update(entry); }
如今討論下傳統的加鎖方法。咱們知道每個對象都隱含了一個鎖,那就是對象自己。咱們能夠在方法體上加上同步字段synchronizedjvm
public synchronized void update(Entry entry){ dao.update(entry); }
但若是方法裏代碼不少,那麼加在方法上會鎖住不少代碼,咱們可使用同步塊性能
public void update(Entry entry){ dobefore(); synchronized(this){ dao.update(entry); } doend(); }
而須要注意的是若是一個類中存在多個同步方法,那麼全部同步方法的鎖都是對象自己,也就是說當執行update的時候,別的線程不只不能執行update連類中別的同步方法也不能使用。固然也可使用一點技巧去規避這個問題,好比使用其餘鎖。this
咱們這篇博客說得不是上面的方法,而是另一個位於java.util.concurrent.locks包下的ReentrantLock。spa
官方是這麼說的:線程
一個可重入的互斥鎖 Lock,它具備與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行爲和語義,但功能更強大。
ReentrantLock 將由最近成功得到鎖,而且尚未釋放該鎖的線程所擁有。當鎖沒有被另外一個線程所擁有時,調用 lock 的線程將成功獲取該鎖並返回。若是當前線程已經擁有該鎖,此方法將當即返回。可使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此狀況是否發生。
此類的構造方法接受一個可選的公平 參數。當設置爲 true 時,在多個線程的爭用下,這些鎖傾向於將訪問權授予等待時間最長的線程。不然此鎖將沒法保證任何特定訪問順序。與採用默認設置(使用不公平鎖)相比,使用公平鎖的程序在許多線程訪問時表現爲很低的整體吞吐量(即速度很慢,經常極其慢),可是在得到鎖和保證鎖分配的均衡性時差別較小。不過要注意的是,公平鎖不能保證線程調度的公平性。所以,使用公平鎖的衆多線程中的一員可能得到多倍的成功機會,這種狀況發生在其餘活動線程沒有被處理而且目前並未持有鎖時。還要注意的是,未定時的 tryLock 方法並無使用公平設置。由於即便其餘線程正在等待,只要該鎖是可用的,此方法就能夠得到成功。code
使用它也很簡單,你能夠用以下結構來使用他: 對象
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
經常使用的方法就如上面所說的同樣,lock和unlock 接口
lock public void lock() 獲取鎖。 若是該鎖沒有被另外一個線程保持,則獲取該鎖並當即返回,將鎖的保持計數設置爲 1。 若是當前線程已經保持該鎖,則將保持計數加 1,而且該方法當即返回。 若是該鎖被另外一個線程保持,則出於線程調度的目的,禁用當前線程,而且在得到鎖以前,該線程將一直處於休眠狀態,此時鎖保持計數被設置爲 1。 指定者: 接口 Lock 中的 lock unlock public void unlock() 試圖釋放此鎖。 若是當前線程是此鎖全部者,則將保持計數減 1。若是保持計數如今爲 0,則釋放該鎖。若是當前線程不是此鎖的持有者,則拋出 IllegalMonitorStateException。 指定者: 接口 Lock 中的 unlock 拋出: IllegalMonitorStateException - 若是當前線程沒有保持此鎖
固然他還有別的不少方法,須要的話能夠本身去看看。
對比synchronized這個鎖是獨立的,在一個類中多個同步塊之間都是獨立的,互不影響。最後說一句,由於同步塊會讓一段代碼同一時刻只能有一個線程使用,多線程同時訪問,一個使用其餘都是等待狀態,那麼就存在一個性能問題。若是理解原子性,又那麼牛X,利用原子性寫出避免同步的免鎖代碼,什麼synchronized啊,ReentrantLock啊,都是浮雲。