Gaurang Agarwal
Gaurang Agarwal

Reputation: 66

Reetrant locks in java

I am new to Multi Threading in java. I was trying to use locks.Here is my code sample.

package com;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class UsingLocks {
Lock lock = new ReentrantLock();
public static void main(String[] args) {
    // TODO Auto-generated method stub


    UsingLocks job = new UsingLocks();
    Thread [] threads= new Thread[5];
    for(int i=0;i<5;i++){
        threads[i]= new Thread(new LockTask(job));
    }
    for(int i=0;i<5;i++){
        threads[i].start();
    }

}

public void lockingJob() {
    System.out.println("Thread "+Thread.currentThread().getName()+" trying to Acquire lock");
    try {
    lock.tryLock();
    //lock.lock(); //When I use this, code works fine
    int time=new Random().nextInt(10)+3;
    System.out.println("Thread "+Thread.currentThread().getName()+" Acquired lock for "+time+" seconds.");
    TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("Now releasing lock "+Thread.currentThread().getName());
    lock.unlock();
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("After Unlock "+Thread.currentThread().getName());



}




}
class LockTask implements Runnable{
UsingLocks job;
public LockTask(UsingLocks job) {
    // TODO Auto-generated constructor stub
    this.job=job;

}

@Override
public void run() {
    // TODO Auto-generated method stub
    job.lockingJob();


}

}

Following is the output when I use tryLock()

Thread Thread-1 trying to Acquire lock
Thread Thread-0 trying to Acquire lock
Thread Thread-2 trying to Acquire lock
Thread Thread-1 Acquired lock for 12 seconds.
Thread Thread-2 Acquired lock for 3 seconds.
Thread Thread-0 Acquired lock for 8 seconds.
Thread Thread-3 trying to Acquire lock
Thread Thread-3 Acquired lock for 9 seconds.
Thread Thread-4 trying to Acquire lock
Thread Thread-4 Acquired lock for 6 seconds.
Now releasing lock Thread-2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at      java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
at com.UsingLocks.lockingJob(UsingLocks.java:37)
at com.LockTask.run(UsingLocks.java:66)
at java.lang.Thread.run(Thread.java:745)
Now releasing lock Thread-4
Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
at com.UsingLocks.lockingJob(UsingLocks.java:37)
at com.LockTask.run(UsingLocks.java:66)
at java.lang.Thread.run(Thread.java:745)

Now, as per my understanding, when the first thread executes tryLock(), it should acquire the lock and other threads should not be able to get lock.But as show in the output.After Thread-1 acquires lock, Thread-2 also acquired lock and so on. How can this be possible. Please tell me what I am missing here. Thanks in advance.

Upvotes: 0

Views: 1916

Answers (5)

javaguy
javaguy

Reputation: 1

The the call to tryLock(), simply returns a boolean, it has "no bearing" on whether the next line/statement, if any, will execute or not. This, is the reason, why tryLock() should be used as a check to do some activities/block of code, which one wants to be synchronized. Hope that answers your question.

Upvotes: 0

duffymo
duffymo

Reputation: 308733

I modified your code a bit and tried it for myself.

I found that ReentrantLock.tryLock would throw an IllegalMonitorStateException no matter what I did. I don't think it's appropriate.

package concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * LockableTask is a nice demonstration
 * @author Michael
 * @link https://stackoverflow.com/questions/32680954/reetrant-locks-in-java
 * @since 9/20/2015 11:25 AM
 */
public class LockableTask implements Runnable {

    private static final int DEFAULT_WAIT = 100;
    private static final int DEFAULT_TIMEOUT = 1000;
    private static final int DEFAULT_THREADS = 5;

    private ReentrantLock lock;
    private int waitPeriod;
    private int timeoutPeriod;
    private boolean halfHeartedLockRequest;

    public static void main(String[] args) {
        long begTime = System.currentTimeMillis();
        System.out.println("Start reentrant lock test");
        try {
            LockableTask lockableTask = new LockableTask(true, false);
            int numThreads = (args.length > 0) ? Integer.parseInt(args[0]) : DEFAULT_THREADS;
            List<Thread> threads = new ArrayList<>(numThreads);
            for (int i = 0; i < numThreads; ++i) {
                threads.add(new Thread(lockableTask));
            }
            for (Thread thread : threads) {
                thread.start();
            }
        } finally {
            long endTime = System.currentTimeMillis();
            System.out.println(String.format("Complete reentrant lock test in %d milliseconds", (endTime-begTime)));
        }
    }

    public LockableTask() {
        this(false, false, DEFAULT_WAIT, DEFAULT_TIMEOUT);
    }

    public LockableTask(boolean halfHeartedLockRequest, boolean fair) {
        this(halfHeartedLockRequest, fair, DEFAULT_WAIT, DEFAULT_TIMEOUT);
    }

    public LockableTask(boolean halfHeartedLockRequest, boolean fair, int waitPeriod, int timeoutPeriod) {
        this.halfHeartedLockRequest = halfHeartedLockRequest;
        this.lock = new ReentrantLock(fair);
        this.waitPeriod = (waitPeriod > 0) ? waitPeriod : DEFAULT_WAIT;
        this.timeoutPeriod = (timeoutPeriod > 0) ? timeoutPeriod : DEFAULT_TIMEOUT;
    }

    @Override
    public void run() {
        System.out.println(String.format("Thread '%s' requests lock ", Thread.currentThread().getName()));
        if (this.halfHeartedLockRequest) {
            this.lock.tryLock();
        } else {
            this.lock.lock();
        }
        try {
            System.out.println(String.format("Thread '%s' acquires lock for %d ", Thread.currentThread().getName(), this.waitPeriod));
            TimeUnit.MILLISECONDS.sleep(this.waitPeriod);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            this.lock.unlock();
            System.out.println(String.format("Thread '%s' releases lock ", Thread.currentThread().getName()));
        }
    }
}

Upvotes: 0

user2953113
user2953113

Reputation: 569

Try something like this to make it more clear.

    System.out.println("Thread "+ Thread.currentThread().getName() + " trying to Acquire lock");
    if (lock.tryLock()) {
        try {
            System.out.println("Lock acquired .. ");
            int time=new Random().nextInt(10)+3;
            System.out.println("Thread " + Thread.currentThread().getName() + " Acquired lock for " + time + " seconds.");
            TimeUnit.SECONDS.sleep(time);
       } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
      }
        finally {
            System.out.println("Now releasing lock "+Thread.currentThread().getName());
            lock.unlock();
        }
    } else {
        System.out.println("Thread "+ Thread.currentThread().getName()+ " Failed to acquire lock .. ");
    }

Upvotes: 0

Subhrajyoti Majumder
Subhrajyoti Majumder

Reputation: 41200

ReentrantLock#tryLock() - Acquires the lock only if it is not held by another thread at the time of invocation & returns true if succeed else false.

If we see the stack-trace -

...
Now releasing lock Thread-2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
...
Now releasing lock Thread-4
Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
...

It is more clear that threads which unable to get the lock, raising exception while trying to release it.

Upvotes: 0

Sathish
Sathish

Reputation: 5173

The reason is that tryLock never blocks if the lock is already held by another thread.

Below is the documentation about the tryLock()

public boolean tryLock()

Acquires the lock only if it is not held by another thread at the time of invocation.

Acquires the lock if it is not held by another thread and returns immediately with the value true, setting the lock hold count to one. Even when this lock has been set to use a fair ordering policy, a call to tryLock() will immediately acquire the lock if it is available, whether or not other threads are currently waiting for the lock. This "barging" behavior can be useful in certain circumstances, even though it breaks fairness. If you want to honor the fairness setting for this lock, then use tryLock(0, TimeUnit.SECONDS) which is almost equivalent (it also detects interruption).

If the current thread already holds this lock then the hold count is incremented by one and the method returns true.

If the lock is held by another thread then this method will return immediately with the value false.

Upvotes: 2

Related Questions