A Callable is like a Runnable except it has a method that returns a Future
Callable looks like this:
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
return example.updateState( 1 );
}
};
They can be executed using an ExecutorService:
ExecutorService executorService = Executors.newFixedThreadPool(1);
List<Callable> callables = new ArrayList<>();
callables.add( callable );
List<Future<Integer> futures = executorService,invokeAll( callables );
Notice that the invokeAll method returns a list of futures. You can iterate through these futures:
for ( Future<Integer> future: futures ) {
Integer result - future.get();
}
The get method blocks until the Callable has finished executing and returned its result.
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.callable
You can run the testng unit test using a testng plugin for your IDE or you can run the main method of:
CallableExampleTest
See: testng
package com.javaspeak.java_examples.concurrency.callable;
/**
*
* @author John Dickerson - 2 Dec 2022
*/
public interface CallableExample {
Integer updateState( Integer amountToAdd );
Integer getState();
}
package com.javaspeak.java_examples.concurrency.callable;
/**
*
* @author John Dickerson - 2 Dec 2022
*/
public class CallableExampleImpl implements CallableExample {
private volatile Integer state = 0;
@Override
public Integer updateState( Integer amountToAdd ) {
synchronized ( this ) {
this.state = this.state + amountToAdd;
return state;
}
}
@Override
public Integer getState() {
return state;
}
}
package com.javaspeak.java_examples.concurrency.callable;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 - 2 Dec 2022
*/
public class CallableExampleTest {
private Logger logger = LoggerFactory.getLogger( CallableExampleTest.class );
private CallableExample example;
@BeforeClass
public void setup() {
example = new CallableExampleImpl();
}
@Test
public void doTest() throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool( 4 );
List<Callable<Integer>> callables = new ArrayList<>();
for ( int i = 0; i < 4; i++ ) {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return example.updateState( 1 );
}
};
callables.add( callable );
}
List<Future<Integer>> futures = executorService.invokeAll( callables );
for ( Future<Integer> future: futures ) {
// The get method blocks until the callable has returned its value
Integer state = future.get();
logger.info( "state = " + state );
}
Integer endState = example.getState();
Assert.assertEquals( endState.intValue(), 4 );
}
public static void main( String[] args ) {
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses( new Class[] { CallableExampleTest.class } );
testng.addListener( tla );
testng.run();
}
}
Back: Concurrency
Page Author: JD