Renentrant Lock is an implementation of the Lock interface. It allows the same thread to aquire the lock as many times as it wants - hence the name "Reentrant".
Please see here for explanation of locks:
The principle idea is that you access or update a shared resource after taking a lock. Once you have finished accessing or updating the shared resource you release the lock. Only one thread at a time can take the lock, so other threads can block for the lock waiting for it to be released.
lock.lock();
try {
return someMethodCallThatUpdatesOrReadsASharedResource();
}
finally {
lock.unlock();
}
The above code is similar to:
public synchronized Integer synchronized() {
return someMethodCallThatUpdatesOrReadsASharedResource();
}
or similar to:
public Integer synchronized() {
sychronized( this ) {
return someMethodCallThatUpdatesOrReadsASharedResource();
}
}
To get the code for this example:
git clone https://github.com/spotadev/java-examples.git
In both src/main/java and src/test/java navigate to this package:
com.javaspeak.java_examples.concurrency.lock.reentrantlock
You can run the testng unit test using a testng plugin for your IDE or you can run the main method of:
ReentrantLockExampleImplTest
package com.javaspeak.java_examples.concurrency.lock.reentrantlock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author John Dickerson - 29 Nov 2022
*/
public interface ReentrantLockExample {
Integer perform(
Score score,
Integer incrementToAddToScore,
ReentrantLock lock );
}
package com.javaspeak.java_examples.concurrency.lock.reentrantlock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author John Dickerson - 28 Nov 2022
*/
public class ReentrantLockExampleImpl implements ReentrantLockExample {
@Override
public Integer perform(
Score score,
Integer incrementToAddToScore,
ReentrantLock lock ) {
lock.lock();
try {
score.addToScore( incrementToAddToScore );
return incrementToAddToScore;
}
finally {
lock.unlock();
}
}
}
package com.javaspeak.java_examples.concurrency.lock.reentrantlock;
/**
* @author John Dickerson - 29 Nov 2022
*/
public class Score {
private Integer score = 0;
public void addToScore( Integer number ) {
this.score = score + number;
}
public Integer getScore() {
return score;
}
}
package com.javaspeak.java_examples.concurrency.lock.reentrantlock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import org.testng.Assert;
import org.testng.TestListenerAdapter;
import org.testng.TestNG;
import org.testng.annotations.Test;
import com.javaspeak.java_examples.concurrency.synchronizedblock.SynchronizedBlockExampleTest;
/**
* @author John Dickerson - 28 Nov 2022
*/
public class ReentrantLockExampleTest {
@Test
public void doTest() throws InterruptedException, ExecutionException {
ReentrantLockExample reentrantLockExample = new ReentrantLockExampleImpl();
ReentrantLock lock = new ReentrantLock();
Score sharedScore = new Score();
ExecutorService executorService = Executors.newFixedThreadPool( 4 );
List<Callable<Integer>> callables = new ArrayList<>();
Integer[] numbers = new Integer[] { 1, 1, 1, 1 };
for ( int i = 0; i < 4; i++ ) {
// needs to be a final as we are passing it into the perform method.
final Integer incrementToAdd = numbers[i];
// Callable is like a Runnable or Thread except it returns a value.
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
return reentrantLockExample.perform( sharedScore, incrementToAdd, lock );
}
};
callables.add( callable );
}
// The futures return straight away but you will notice that below we block on the get
// method of each future. The future returns the value returned by the callable.
List<Future<Integer>> futures = executorService.invokeAll( callables );
int count = 0;
for ( Future<Integer> future : futures ) {
// the future.get() method blocks until the Callable has finished executing and
// returned its value
count = count + future.get();
}
Assert.assertEquals( count, 4 );
Assert.assertEquals( sharedScore.getScore().intValue(), 4 );
}
public static void main( String[] args ) {
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses( new Class[] { SynchronizedBlockExampleTest.class } );
testng.addListener( tla );
testng.run();
}
}
Back: Locks Explained | Concurrency
Page Author: JD