Conditions allow you to block until a certain condition is met
Conditions are retrieved from a lock:
private Condition dequeEmptyCondition = lock.newCondition();
private Condition dequeFullCondition = lock.newCondition();
The condition has methods:
await()
signallAll()
The idea is that you call the await() method on a Condition and it will remain blocked until another thread calls the signallAll() method on the same condition.
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.reentrantlockwithcondition
You can run the testng unit test using a testng plugin for your IDE or you can run the main method of:
ReentrantLockWithConditionTest
package com.javaspeak.java_examples.concurrency.lock.reentrantlockwithcondition;
/**
* @author John Dickerson - 27 Dec 2022
*/
public interface ReentrantLockWithCondition {
void pushToDeque( String item ) throws InterruptedException;
String popFromDeque() throws InterruptedException;
int getSizeOfDeque();
}
package com.javaspeak.java_examples.concurrency.lock.reentrantlockwithcondition;
import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author John Dickerson - 26 Dec 2022
*/
public class ReentrantLockWithConditionImpl implements ReentrantLockWithCondition {
private Deque<String> deque = new LinkedList<>();
private int capacity = 5;
private ReentrantLock lock = new ReentrantLock();
private Condition dequeEmptyCondition = lock.newCondition();
private Condition dequeFullCondition = lock.newCondition();
public ReentrantLockWithConditionImpl( int capacity ) {
this.capacity = 5;
}
@Override
public int getSizeOfDeque() {
return deque.size();
}
@Override
public void pushToDeque( String item ) throws InterruptedException {
try {
lock.lock();
while ( deque.size() == capacity ) {
dequeFullCondition.await();
}
deque.push( item );
dequeEmptyCondition.signalAll();
}
finally {
lock.unlock();
}
}
@Override
public String popFromDeque() throws InterruptedException {
try {
lock.lock();
while ( deque.size() == 0 ) {
dequeEmptyCondition.await();
}
return deque.removeFirst();
}
finally {
dequeFullCondition.signalAll();
lock.unlock();
}
}
}
package com.javaspeak.java_examples.concurrency.lock.reentrantlockwithcondition;
import java.util.concurrent.CountDownLatch;
import org.testng.Assert;
import org.testng.TestListenerAdapter;
import org.testng.TestNG;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* @author John Dickerson - 24 Dec 2022
*/
public class ReentrantLockWithConditionTest {
private static int CAPACITY = 5;
private ReentrantLockWithCondition reentrantLockWithCondition;
@BeforeClass
public void setUp() {
reentrantLockWithCondition = new ReentrantLockWithConditionImpl( CAPACITY );
}
@Test
public void doTest() throws Exception {
reentrantLockWithCondition.pushToDeque( "1" );
Assert.assertEquals( reentrantLockWithCondition.getSizeOfDeque(), 1 );
reentrantLockWithCondition.pushToDeque( "2" );
Assert.assertEquals( reentrantLockWithCondition.getSizeOfDeque(), 2 );
reentrantLockWithCondition.pushToDeque( "3" );
Assert.assertEquals( reentrantLockWithCondition.getSizeOfDeque(), 3 );
reentrantLockWithCondition.pushToDeque( "4" );
Assert.assertEquals( reentrantLockWithCondition.getSizeOfDeque(), 4 );
reentrantLockWithCondition.pushToDeque( "5" );
Assert.assertEquals( reentrantLockWithCondition.getSizeOfDeque(), 5 );
CountDownLatch countDownLatch = new CountDownLatch( 1 );
Thread thread = new Thread() {
public void run() {
try {
// capacity has been reached so it will block on push
reentrantLockWithCondition.pushToDeque( "6" );
countDownLatch.countDown();
System.out.println( "Pushed" );
}
catch ( InterruptedException e ) {
}
}
};
thread.start();
// waiting for Thread to start and block on push method.
Thread.sleep( 1000 );
// this will free up the blocked thread
reentrantLockWithCondition.popFromDeque();
System.out.println( "Popped" );
countDownLatch.await();
Assert.assertEquals( reentrantLockWithCondition.getSizeOfDeque(), 5 );
}
public static void main( String[] args ) {
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses( new Class[] { ReentrantLockWithConditionTest.class } );
testng.addListener( tla );
testng.run();
}
}
Back: Locks Explained | Concurrency
Page Author: JD