St.Antario
St.Antario

Reputation: 27375

Using ReentrantLock instead of synchronized for improving performance

I'm trying to find the most optimal solution for my particular situation.

I currently have the following class:

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
        }
    }
}

The class represents all updates of amount of money shared by a user group. The group may consist up to 100 users. The amount field may be updated by any user of the group concurrently.

Calling the update(int) includes entering two synchronized blocks which is not very good from performance standpoint. Also it may happen that the BULK operation will be computed twice or more times even if there is no need for it. Actually, assume that three threads are trying to acces update() concurrently. The check(date) returned true in each of the threads. It doesn't do any harm, but the BULK operation is quite heavy (more thaqn 1 minute). So, it's critical to not perform it even twice if there is no need.

It's not possible to wrap the BULK operation into a synchronized block becuase it includes calling a couple of alien methods. So, I tend to use ReentrantLock instead of synchronization. The class then may be rewritten as follows:

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
    }
}

QUESTION: Is such using of ReentrantLock more efficient in such circumstances than explicit synchronization.

Upvotes: 0

Views: 182

Answers (1)

Davide Lorenzo MARINO
Davide Lorenzo MARINO

Reputation: 26926

You can do the same without synchronization.

Synchronization is needed only if a thread needs to know the value of a variable to update it. If the thread only change a variable it is sufficient to define it as 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
    }
}

NOTE: A synchronization can be necessary if the amount depends on the actual amount value. A synchronization for date is not necessary

Upvotes: 1

Related Questions