2015-11-13 68 views
0

我正在嘗試爲我的特定情況找到最佳解決方案。使用ReentrantLock而不是同步來提高性能

目前,我有以下類:

public class Container 

    private volatile Date date; 
    private int amount; 
    private final Object lock = new Object(); 

    public void update(int amount){ 
     int actualAmount; 
     if(check(date)){ 
       //do some BULK computation to compute the actualAmount 
      synchronized(lock){ 
       date = new Date(); 
       this.amount = actualAmount; 
      } 
     } 
    } 

    private boolean check(Date date){ 
     synchronized(lock){ 
      //reading from the date and returning true if the date is expired 
     } 
    } 
} 

類代表的用戶羣共享金額的所有更新。該組可能包含100個用戶。 amount字段可以由該組的任何用戶同時更新。

調用update(int)包括輸入兩個同步塊,從性能角度來看這不是很好。即使沒有必要,也可能發生BULK操作將被計算兩次或更多次。實際上,假設三個線程正試圖同時訪問update()check(date)在每個線程中都返回true。它不會造成任何傷害,但操作非常繁重(更多時間爲1分鐘)。所以,如果沒有必要,甚至兩次執行它也是非常重要的。

不可能將BULK操作包裝到同步塊中,因爲它包括調用幾個外來方法。所以,我傾向於使用ReentrantLock而不是同步。類則可以改寫爲:

public class Container 

    private volatile Date date; 
    private int amount; 
    private final Lock lock = new ReentrantLock(); 

    public void update(int amount){ 
     int actualAmount; 
     lock.lock(); 
     try{ 
      if(check(date)){ 
       //do some BULK computation to compute the actualAmount 
       date = new Date(); 
       this.amount = actualAmount; 
      } 
     } finally { 
      lock.unlock(); 
     } 
    } 

    private boolean check(Date date){ 
     //reading from the date and returning true if the date is expired 
    } 
} 

問題:是這樣使用的ReentrantLock在這樣的情況下比顯synchronization更有效。

+2

爲什麼你認爲不可能使用同步塊?你的'update()'方法鎖定一個鎖,然後它執行一些操作,然後解鎖鎖。與'synchronized'塊中的某些東西有什麼不同? –

+0

@ jameslarge因爲我不確定BULK計算是幹什麼樣的工作人員。 –

+0

那麼?你的'update()'方法鎖定一個鎖,它會做一些事情,然後它確保在返回之前鎖將被解鎖。一個'synchronized'塊做了完全相同的事情:它鎖定一個鎖,它做了一些事情,然後它確保鎖將被解鎖。兩種情況下的「東西」無關緊要。方法void update(int amount)中的 –

回答

1

您可以在沒有同步的情況下執行相同操作。

只有當線程需要知道變量的值才能更新它時,才需要同步。如果線程只改變一個變量,那麼將其定義爲volatile就足夠了。

public class Container 

    private volatile Date date; 
    private volatile int amount; 

    public void update(int amount){ 
     int actualAmount; 
     if (check(date)) { 
       //do some BULK computation to compute the actualAmount 

      date = new Date(); 
      this.amount = actualAmount; 
     } 
    } 

    private boolean check(Date date) { 

      //reading from the date and returning true if the date is expired 
    } 
} 

注意:如果該量取決於實際量值同步是必要的。日期同步不是必需的

+0

但是,如果其他線程在批量操作仍在進行時調用該方法? –

+0

註釋「做一些BULK計算」代表可能需要知道一個或多個變量的值才能更新它們的代碼。 –

+0

@詹姆斯我在筆記中添加了信息以正確顯示。請注意,actualAmount可能不取決於金額。 –

相關問題