天天看點

java多線程加鎖的簡單處理辦法 原

    當對資料修改時,如果兩個線程同時去修改同一條資料,這樣産生的結果就不是我們預期的結果。這時候就需要對修改操作進行加鎖,讓jvm裡同一時刻隻能有一個線程能夠執行修改方法。

    下面是一個未加鎖的修改方法:   

public void update(Entry entry){
    dao.update(entry);
}           

複制

    現在讨論下傳統的加鎖方法。我們知道每一個對象都隐含了一個鎖,那就是對象本身。我們可以在方法體上加上同步字段synchronized

public synchronized void update(Entry entry){
    dao.update(entry);
}           

複制

但如果方法裡代碼很多,那麼加在方法上會鎖住很多代碼,我們可以使用同步塊

public void update(Entry entry){
    dobefore();
    synchronized(this){
        dao.update(entry);
    }
    doend(); 
}           

複制

    而需要注意的是如果一個類中存在多個同步方法,那麼所有同步方法的鎖都是對象本身,也就是說當執行update的時候,别的線程不僅不能執行update連類中别的同步方法也不能使用。當然也可以使用一點技巧去規避這個問題,比如使用其他鎖。

    我們這篇部落格說得不是上面的方法,而是另外一個位于java.util.concurrent.locks包下的ReentrantLock。

    官方是這麼說的:

    一個可重入的互斥鎖 Lock,它具有與使用 synchronized 方法和語句所通路的隐式螢幕鎖相同的一些基本行為和語義,但功能更強大。

    ReentrantLock 将由最近成功獲得鎖,并且還沒有釋放該鎖的線程所擁有。當鎖沒有被另一個線程所擁有時,調用 lock 的線程将成功擷取該鎖并傳回。如果目前線程已經擁有該鎖,此方法将立即傳回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此情況是否發生。

    此類的構造方法接受一個可選的公平 參數。當設定為 true 時,在多個線程的争用下,這些鎖傾向于将通路權授予等待時間最長的線程。否則此鎖将無法保證任何特定通路順序。與采用預設設定(使用不公平鎖)相比,使用公平鎖的程式在許多線程通路時表現為很低的總體吞吐量(即速度很慢,常常極其慢),但是在獲得鎖和保證鎖配置設定的均衡性時差異較小。不過要注意的是,公平鎖不能保證線程排程的公平性。是以,使用公平鎖的衆多線程中的一員可能獲得多倍的成功機會,這種情況發生在其他活動線程沒有被處理并且目前并未持有鎖時。還要注意的是,未定時的 tryLock 方法并沒有使用公平設定。因為即使其他線程正在等待,隻要該鎖是可用的,此方法就可以獲得成功。

    使用它也很簡單,你可以用如下結構來使用他:   

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啊,都是浮雲。