Open In App

Runnable, Callable, Future, Executor in Java & Android Multithreaded Programming

Last Updated : 10 Jan, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Multithreading is a Java feature that allows concurrent execution of two or more parts of a program for maximum utilization of CPU. Each part of such a program is called a thread. So, threads are lightweight processes within a process.

Runnable

Any class whose instances are intended to be executed by a thread should implement the Runnable interface. The class must define a run method with no arguments. This interface is intended to provide a standard protocol for objects that want to run code while they are active. Thread, for example, implements the Runnable interface. Being active simply means that a thread has begun and has not yet been terminated. Furthermore, Runnable allows a class to be active while not subclassing Thread. A class that implements Runnable can execute code without subclassing Thread by creating a Thread instance and passing itself as the target.

To create a new Thread with Runnable, follow these steps:

  1. Make a Runnable implementer and call the run() method.
  2. Create a Thread instance and pass the implementer to it. Thread has a function Object() { [native code] } that accepts Runnable instances.
  3. Call start() on the Thread instance; start calls the implementer’s run() internally. Invoking start() generates a new Thread that executes the code specified in run ().

Java




public class Comment implements Activity {
    private Date GeeksCreatedAt;
    public Comment(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
    @Override public Date getCoursesAddedAt()
    {
        return GeeksCreatedAt;
    }
    @Override public String toString()
    {
        return "Comment{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}
public class GfG implements Activity {
 
    private Date GeeksCreatedAt;
 
    public GfG(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
 
    @Override public Date getCoursesAddedAt()
    {
        return GeeksCreatedAt;
    }
 
    @Override public String toString()
    {
        return "GfG{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}


Callable

A task that produces a result and has the ability to throw an exception. Implementers define a single method called call that takes no arguments. The Callable interface is similar to the Runnable interface in that both are intended for classes whose instances may be executed by another thread. A Runnable, on the other hand, does not return a value and cannot throw a checked exception. Executors contain utility methods for converting from other common forms to Callable classes. In order to implement a Runnable, the run() method must be implemented, which does not return anything, whereas, in order to implement a Callable, the call() method must be implemented, which returns a result on completion. It is important to note that a thread cannot be created with a Callable; only a Runnable can do so. Another distinction is that the call() method can throw an exception, whereas the run() method cannot.

Java




public class Like implements Activity {
    private Date GeeksCreatedAt;
 
    public Like(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
 
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
 
    @Override public String toString()
    {
        return "Like{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}


Java




public class Post implements Activity {
    private Date GeeksCreatedAt;
    public Post(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
 
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
 
    @Override public String toString()
    {
        return "Post{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}


Future

A Future is the outcome of an asynchronous computation. Methods are provided to determine whether the computation is complete, to wait for its completion, and to retrieve the computation’s result. When the computation is finished, the result can only be retrieved using method get, blocking if necessary until it is ready. The cancel method is used to cancel a transaction. Additional methods are provided to determine whether or not the task was completed normally. Once a computation has been completed, it cannot be canceled. If you want to use a Future for cancellability but not provide a usable result, you can declare Future? types and return null as a result of the underlying task. Because it implements the Future interface, all interactions with the thread after it starts are handled by the FutureTask object. As a result, there is no need to save the Thread objects. The FutureTask object can be used to cancel the task, check if it is complete, or try to retrieve the result.

Java




public class RemoteService {
    private static int cores
        = Runtime.getRuntime().availableProcessors();
    private static ExecutorService executor
        = Executors.newFixedThreadPool(cores + 1);
    public void stop() { executor.shutdown(); }
    public void
    getUserRecentGfgActs(ResultCallback callback)
    {
        executor.execute(() -> {
            List<Like> gfgLikes = new ArrayList<>();
            List<Post> gfgPOsts = new ArrayList<>();
            List<Comment> comments = new ArrayList<>();
            List<Friend> gfgCourses = new ArrayList<>();
            Future<List<Like> > futureGfgLikes
                = executor.submit(getGfgLikes(
                    "https://geeksforgeeks.org.com/gfgLikes"));
            Future<List<Comment> > futureComments
                = executor.submit(getComments(
                    "https://geeksforgeeks.org.com/comments"));
            Future<List<Post> > futureGfgPOsts
                = executor.submit(getGfgPOsts(
                    "https://geeksforgeeks.org.com/gfgPOsts"));
            Future<List<Friend> > futureGfgCourses
                = executor.submit(getGfgCourses(
                    "https://geeksforgeeks.org.com/gfgCourses"));
 
            try {
                gfgLikes = futureGfgLikes.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
 
            try {
                gfgPOsts = futureGfgPOsts.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
 
            try {
                comments = futureComments.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
 
            try {
                gfgCourses = futureGfgCourses.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
 
            List<Activity> gfgActs = new ArrayList<>();
            gfgActs.addAll(gfgLikes);
            gfgActs.addAll(gfgPOsts);
            gfgActs.addAll(comments);
            gfgActs.addAll(gfgCourses);
 
            Collections.sort(
                gfgActs,
                (activity1, activity2)
                    -> activity1.getCreatedAt().compareTo(
                        activity2.getCreatedAt()));
 
            callback.onResult(gfgActs);
        });
    }
 
    private Callable<List<Like> > getGfgLikes(String url)
    {
        return () ->
        {
            System.out.println("getGfgLikes");
            Thread.sleep(200);
            return Arrays.asList(
                new Like(new Date(1534334348560L)),
                new Like(new Date(1554365436546960L)));
        };
    }
 
    private Callable<List<Post> > getGfgPOsts(String url)
    {
        return () ->
        {
            System.out.println("getGfgPOsts");
            Thread.sleep(500);
            return Arrays.asList(
                new Post(new Date(15334343448560L)),
                new Post(new Date(153343434460L)));
        };
    }
 
    private Callable<List<Comment> > getComments(String url)
    {
        return () ->
        {
            System.out.println("getComments");
            Thread.sleep(200);
            return Arrays.asList(
                new Comment(new Date(15356565648560L)),
                new Comment(new Date(151454545456460L)));
        };
    }
 
    private Callable<List<Friend> >
    getGfgCourses(String url)
    {
        return () ->
        {
            System.out.println("getGfgCourses");
            Thread.sleep(6500);
            return Arrays.asList(
                new Friend(new Date(1534543354248560L)),
                new Friend(new Date(15334343546460L)));
        };
    }
}


Executor

An object that executes Runnable tasks that have been submitted. This interface allows you to decouple task submission from the mechanics of how each task will be executed, such as thread usage, scheduling, and so on. Instead of explicitly creating threads, an Executor is typically used. Instead of invoking new Thread(new(RunnableTask())), for example. start() for each task in a sequence. It is, as the name implies, a thread pool with a fixed number of threads. The tasks submitted to the executor are executed by the n threads, and any additional tasks are stored on a LinkedBlockingQueue. It employs a Blocking Queue.

Creating and Running a Simple Executor, in which we will create a task and run it in a fixed pool.

  1. The Task class implements Callable and has a String parameter. It is also stated that it will throw an exception.
  2. To execute a task in the class “Task,” we must first instantiate the Task class and pass it to the executor for execution.
  3. The Future object’s result should be printed and displayed.


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads