Home > OS >  How to lock a sequence of methods, such that other thread call those same method should be waiting?
How to lock a sequence of methods, such that other thread call those same method should be waiting?

Time:03-18

Suppose there is one Thread and it has a sequence of methods to be executed:

public void task(){
   method();
   method();
   method();
   method();
}

I would like to lock the whole sequence. That is, when that task() is executing, I don't want the other threads to execute the same method() but to wait until the whole task() is done. What kinds of lock is needed?

CodePudding user response:

You could either make that task synchronized:

public synchronized void task() {
    method();
    method();
    method();
    method();
}

This will prevent other threads from calling the same task() method on the same object, including other synchronized methods on that object. You can have more control with an explicit synchronized statement, like

public void task() {
    synchronized (this) { // or another object
        method();
        method();
        method();
        method();
    }
}

Or use your own Lock instance:

private final ReentrantLock lock = new ReentrantLock();
public void task() {
    lock.lock();  // block until lock is released
    try {
        method();
        method();
        method();
        method();
    } finally {
        lock.unlock();
    }
}

If you want to have all method() calls not to be running at the same time, just apply the same mechanism to the method() declaration:

public synchronized void method() // or one of the other two options

If you apply one of these three mechanisms to both task and method, you would make sure, that the thread calling task() will finish all method() calls sequentially and prevent other threads from calling any method() meanwhile. Both synchronized and the ReentrantLock allow the same thread to get the same lock/monitor multiple times (nested locks).

Finally, if you want to allow multiple parallel calls to method() but just not while task() is executed, you'd need a shared or read-write lock (see ReentrantReadWriteLock).

CodePudding user response:

you need to have a shared Lock of some kind, and pass it's reference to all threads that need to execute the sequence.

for instance, create a public static final ReentrantLock LOCK = new ReentrantLock(); on the class which has the task() method and in the beginning of the method task() write LOCK.lock(); and LOCK.unlock(); at the end. now, all threads passing through the task() method will try to acquire the lock, and it will block them if its already taken.

CodePudding user response:

This can be an option but may not be the best. You could modify the signature of your method() in this way:

public void method(int serialExecutionCount) {
    synchronized(this) {
        for (int i = 0; i < serialExecutionCount; i  ) {
            // body of your method()
        }
    }
}

Now, your task() method will be like this:

public void task() {
   method(4);
}

Now, if you call it from other thread like this:

method(1);

it will wait for previous 4 method calls to be finished from task() method's calling thread.

  • Related