Motivation
- learning in depth about the Callable and Runnable
Difference
- Runnable does not returns a result and cannot throw a checked exception
- Callable can returns a result and can throw a checked exception
- Callable can only be ran by Executor Service whereas the runnable can be ran by Thread as well as Executor Service.
Why Runnable is still there ?
- since Callable can do everything than Runnable can do but still Runnable is there since Callable is introduced in 1.5 and before that we have Runnable only so if the java team will modify the Runnable all the older programs running older java version will break and that's not how java works that is not their selling point, their selling point is backward compatibility.
Some more points to remember
A Callable needs to implement call() method while a Runnable needs to implement run() method. A Callable can return a value but a Runnable cannot. A Callable can throw checked exception but a Runnable cannot. A Callable can be used with ExecutorService#invokeXXX(Collection<? extends Callable> tasks) methods but a Runnable cannot be.
public interface Runnable { void run(); }
public interface Callable { V call() throws Exception; }
Example of Callable with Futures
import java.util.*;
import java.util.concurrent.*;
public class index {
public static void main(String args[]) throws InterruptedException, ExecutionException {
long starttime = System.currentTimeMillis();
NewObjectCreator obj = new NewObjectCreator();
Future<List<Employee>> future1 = obj.createdNewObjectsAndSave(0, 4);
Future<List<Employee>> future2 = obj.createdNewObjectsAndSave(5, 9);
while (!(future1.isDone() && future2.isDone())) {
System.out.println(String.format(
"future1 is %s and future2 is %s",
future1.isDone() ? "done" : "not done",
future2.isDone() ? "done" : "not done"
)
);
Thread.sleep(300);
}
if (future1.isDone() && future2.isDone()) {
obj.shutdownExecutor();
List<Employee> fe1 = future1.get();
List<Employee> fe2=future2.get();
for(Employee e: fe1) {
System.out.println(e.getId());
}
for(Employee e: fe2) {
System.out.println(e.getId());
}
}
System.out.println("Time Taken to complete the traversing and addition is " + (System.currentTimeMillis() - starttime));
}
}
class NewObjectCreator {
// converted normal list to synchronsied list so that all the threads can write on a singele list
// and it is thread safe since otherwise one thread is reading and
List<Employee> FinalObject = Collections.synchronizedList( new ArrayList<>());
private ExecutorService executorService = Executors.newFixedThreadPool(2);
public Future<List<Employee>> createdNewObjectsAndSave(int start, int end) throws InterruptedException {
//submitting the task to the executer service
// here we can also make it runnable --> but with runnable we will not be able to return anything
Callable<List<Employee>> c1= () -> {
for (int i = start; i < end; i++) {
Employee e1 = new Employee();
e1.setId(i);
e1.setName(i + "test name");
e1.setDep(i + "test department");
e1.setSeatNumber(i * 2);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
FinalObject.add(e1);
}
return FinalObject;
};
// return executorService.submit(() -> {
//
// for (int i = start; i < end; i++) {
//
// Employee e1 = new Employee();
// e1.setId(i);
// e1.setName(i + "test name");
// e1.setDep(i + "test department");
// e1.setSeatNumber(i * 2);
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// FinalObject.add(e1);
// }
//
// return FinalObject;
//
// });
return executorService.submit(c1);
}
public void shutdownExecutor() {
executorService.shutdown();
}
}
class Employee {
private int id;
private String name;
private String dep;
private int seatNumber;
Employee() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDep(String dep) {
this.dep = dep;
}
public void setSeatNumber(int seatNumber) {
this.seatNumber = seatNumber;
}
}