2015-11-13 32 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可能不取决于金额。 –

相关问题