What is callable in java

What is the difference between runnable and callable in Java?

Many candidates are rejected or down-leveled in technical interviews due to poor performance in behavioral or cultural fit interviews. Ace your interviews with this free course, where you will practice confidently tackling behavioral interview questions.

Both runnable and callable interfaces are designed for classes. Their instances are supposed to be executed by another thread.

However, there are also some differences between these interfaces. Let’s discuss the differences between them by explaining them separately.

Callable interface

A callable interface throws the checked exception and returns the result. A runnable interface, on the other hand, does not return a result and cannot throw a checked exception.

Syntax

public interface Callable

  • We declare it in the package named java.util.concurrent .
  • It consists of the call() method with no arguments.
  • A programmer cannot create a new thread by passing the callable interface as a parameter.
  • The callable interface can return results.

Example

The example below illustrates the usage of the callable interface.

  • On line #8 we create a class named EdPresso which extends the Callable interface.
  • On line #19 we create a pool of threads of size 5. In the highlighted lines, we create the EdPresso object, which is a list to hold the Future object list.
  • Whenever an asynchronous task is created, a future object is returned.
// importing build-in classes
import java.util.concurrent.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
// class impelementing callable interface
public class EdPresso implements Callable
@Override // overriding method
public String call() throws Exception
Thread.sleep(500);
//return the thread name executing this callable task
return Thread.currentThread().getName();
>
// main method starting here
public static void main(String args[])
// Thread pool size is 5
ExecutorService exe = Executors.newFixedThreadPool(5);
//Create EdPresso instance
Callable callable = new EdPresso();
//create a list to hold the Future object associated with Callable
List mylist = new ArrayList();
for(int i=0; i< 50; i++)
//submit Callable tasks to be executed by thread pool
Future store = exe.submit(callable);
//add Future to the list, we can get return value using Future
mylist.add(store);
>
for(Future i: mylist)
try
// because Future.get() waits for task to get completed
System.out.println(new Date()+ "::"+i.get());
> catch (InterruptedException | ExecutionException e)
e.printStackTrace();
>
>
//shut down the service now
exe.shutdown();
>
>

Runnable interface

It is required to create a thread when a runnable interface is implemented through an object.

The thread contains a single method named run() that does not return any value or accept any parameters.

Syntax

public interface Runnable

Example

The example below illustrates the usage of the runnable interface.

As highlighted, we create an object of EdPresso type and an object of thread type thread . It is called after the main method thread completes its execution.

Источник

What is callable in java

Interface Callable

  • Type Parameters: V — the result type of method call All Known Subinterfaces: DocumentationTool.DocumentationTask , JavaCompiler.CompilationTask All Known Implementing Classes: JavacTask Functional Interface: This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
@FunctionalInterface public interface Callable

A task that returns a result and may throw an exception. Implementors define a single method with no arguments called call . The Callable interface is similar to Runnable , in that both are designed for classes whose instances are potentially executed by another thread. A Runnable , however, does not return a result and cannot throw a checked exception. The Executors class contains utility methods to convert from other common forms to Callable classes.

Method Summary

Method Detail

call

Report a bug or suggest an enhancement
For further API reference and developer documentation see the Java SE Documentation, which contains more detailed, developer-targeted descriptions with conceptual overviews, definitions of terms, workarounds, and working code examples.
Java is a trademark or registered trademark of Oracle and/or its affiliates in the US and other countries.
Copyright © 1993, 2023, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
All rights reserved. Use is subject to license terms and the documentation redistribution policy.

Источник

Thread’ом Java не испортишь: Часть IV — Callable, Future и друзья

Java-университет

Thread

Мы уже рассматривали в первой части, как создаются потоки. Ещё раз вспомним. Поток — это Thread , в нём что-то запускается run , поэтому воспользуемся tutorialspoint java online compiler’ом и выполним следующий код:

 public class HelloWorld < public static void main(String []args)< Runnable task = () ->< System.out.println("Hello World"); >; new Thread(task).start(); > > 

java.util.concurrent.Callable

Оказывается, у java.lang.Runnable есть брат и зовут его java.util.concurrent.Callable и появился он на свет в Java 1.5. В чём же различия? Если приглядеться к JavaDoc этого интерфейса, мы видим, что в отличие от Runnable , новый интерфейс объявляет метод call , который возвращает результат. Кроме того, по умолчанию он throws Exception. То есть избавляет нас от необходимости на проверяемые исключения писать try-catch блоки. Уже неплохо, правда? Теперь у нас есть вместо Runnable новый task:

Но что с ним делать? Зачем нам вообще задача, выполняемая в потоке, которая возвращает результат? Очевидно, что в дальнейшем мы рассчитываем получить результат действий, которыев в будущем будут выполнены. Будущее по-английский — Future. И интерфейс есть с точно таким же именем: java.util.concurrent.Future

java.util.concurrent.Future

Интерфейс java.util.concurrent.Future описывает API для работы с задачами, результат которых мы планируем получить в будущем: методы получения результата, методы проверки статуса. Для Future нас интересует его реализация java.util.concurrent.FutureTask. То есть это Task , который будет выполнен во Future . Чем эта реализация ещё интересна, так это тем, что она реализует и Runnable . Можно считать это своего рода адаптером старой модели работы с задачами в потоках и новой модели (новой в том смысле, что она появилась в java 1.5). Вот пример:

 import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class HelloWorld < public static void main(String []args) throws Exception < Callable task = () ->< return "Hello, World!"; >; FutureTask future = new FutureTask<>(task); new Thread(future).start(); System.out.println(future.get()); > > 

Как видно из примера, мы получаем при помощи метода get результат из задачи task . (!)Важно , что в момент получения результата при помощи метода get выполнение становится синхронным. Как вы думаете, какой механизм тут будет использован? Правильно, нет блока синхронизации — поэтому WAITING в JVisualVM мы увидим не как monitor или wait , а как тот самый park (т.к. используется механизм LockSupport ).

Функциональные интерфейсы

Дальше пойдёт речь про классы из Java 1.8, поэтому не лишним будет сделать краткое введение. Посмотрим на следующий код:

 Supplier supplier = new Supplier() < @Override public String get() < return "String"; >>; Consumer consumer = new Consumer() < @Override public void accept(String s) < System.out.println(s); >>; Function converter = new Function() < @Override public Integer apply(String s) < return Integer.valueOf(s); >>; 

Как же много лишнего кода, не правда ли? Каждый из объявляемых классов выполняет какую-то одну функцию, но для её описания мы используем кучу лишнего вспомогательного кода. И разработчики Java так же подумали. Поэтому, они ввели набор «функциональных интерфейсов» ( @FunctionalInterface ) и решили, что теперь Java сама будет «додумывать» за нас всё, кроме важного:

 Supplier supplier = () -> "String"; Consumer consumer = s -> System.out.println(s); Function converter = s -> Integer.valueOf(s); 

Supplier — поставщик. Он не имеет параметров, но возвращает что-то, то есть поставляет это. Consumer — потребитель. Он принимает на вход что-то (параметр s) и с этим что-то что-то делает, то есть потребляет что-то. Есть ещё функция. Она принимает на вход что-то (параметр s ), что-то делает и возвращает что-то. Как мы видим, активно используются дженерики. В случае неуверенности можно вспомнить про них и прочитать «Теория дженериков в Java или как на практике ставить скобки».

CompletableFuture

Thread

Шло время, и в Java 1.8 появился новый класс, который зовётся CompletableFuture . Он реализует интерфейс Future , то есть наши task будут выполнены в будущем, и мы сможем выполнить get и получить результат. Но ещё он реализует некоторый CompletionStage . Из перевода уже понятно его назначение: это некий этап (Stage) каких-то вычислений. С кратким введением в тему можно ознакомиться в обзоре «Introduction to CompletionStage and CompletableFuture». Давайте перейдём сразу к делу. Посмотрим на список доступных статических методов, которые нам помогут начать: Вот варианты их использования:

 import java.util.concurrent.CompletableFuture; public class App < public static void main(String []args) throws Exception < // CompletableFuture уже содержащий результат CompletableFuturecompleted; completed = CompletableFuture.completedFuture("Просто значение"); // CompletableFuture, запускающий (run) новый поток с Runnable, поэтому он Void CompletableFuture voidCompletableFuture; voidCompletableFuture = CompletableFuture.runAsync(() -> < System.out.println("run " + Thread.currentThread().getName()); >); // CompletableFuture, запускающий новый поток, результат которого возьмём у Supplier CompletableFuture supplier; supplier = CompletableFuture.supplyAsync(() -> < System.out.println("supply " + Thread.currentThread().getName()); return "Значение"; >); > > 

Если мы выполним этот код, то увидим, что создание CompletableFuture подразумевает запуск и всей цепочки. Поэтому при некоторой схожести со SteamAPI из Java8 в этом отличие этих подходов. Например:

 List array = Arrays.asList("one", "two"); Stream stringStream = array.stream().map(value -> < System.out.println("Executed"); return value.toUpperCase(); >); 
  • У нас есть функция ( Function ), которая принимает А и возвращает Б. Имеет единственный метод — apply (применить).
  • У нас есть потребитель ( Consumer ), которая принимает А и ничего не возвращает (Void). Имеет единственный метод — accept (принять).
  • У нас есть запускаемый в потоке код Runnable , который не принимает и не возвращает. Имеет единственный метод — run (запустить).
 public static void main(String []args) throws Exception < AtomicLong longValue = new AtomicLong(0); Runnable task = () ->longValue.set(new Date().getTime()); Function dateConverter = (longvalue) -> new Date(longvalue); Consumer printer = date -> < System.out.println(date); System.out.flush(); >; // CompletableFuture computation CompletableFuture.runAsync(task) .thenApply((v) -> longValue.get()) .thenApply(dateConverter) .thenAccept(printer); > 

У методов thenRun , thenApply и thenAccept есть версии Async . Это значит, что эти стадии будут выполнены в новом потоке. Он будет взят из особого пула, поэтому заранее неизвестно, какой поток будет, новый или прежний. Всё зависит от того, на сколько тяжёлые задачи. Помимо этих методов есть ещё три интересные возможности. Для наглядности представим, что у нас есть некий сервис, который получает какое-то сообщение откуда-то и на это требуется время:

 public static class NewsService < public static String getMessage() < try < Thread.currentThread().sleep(3000); return "Message"; >catch (InterruptedException e) < throw new IllegalStateException(e); >> > 

Теперь, давайте посмотрим на другие возможности, которые предоставляет CompletableFuture . Мы можем объединять результат CompletableFuture с результатом другого CompletableFuture :

 Supplier newsSupplier = () -> NewsService.getMessage(); CompletableFuture reader = CompletableFuture.supplyAsync(newsSupplier); CompletableFuture.completedFuture("!!") .thenCombine(reader, (a, b) -> b + a) .thenAccept(result -> System.out.println(result)) .get(); 

Тут стоить обратить внимание, что по умолчанию потоки будут демон-потоками, поэтому для наглядности мы используем get , чтобы дождаться результат. А ещё мы можем не только объединить (combine), но и возвращать CompletableFuture :

 CompletableFuture.completedFuture(2L) .thenCompose((val) -> CompletableFuture.completedFuture(val + 2)) .thenAccept(result -> System.out.println(result)); 

Thread

Тут хочется отметить, что для краткости использован метод CompletableFuture.completedFuture . Данный метод не создаёт новый поток, поэтому остальная цепочка будет выполнена в том же потоке, в котором был вызван completedFuture . Также есть метод thenAcceptBoth . Он очень похож на accept , но если thenAccept принимает consumer , то thenAcceptBoth принимает на вход ещё один CompletableStage + BiConsumer , то есть consumer , который на вход принимает 2 источника, а не один. Есть ещё интересная возможность со словом Either : Данные методы принимают альтернативный CompletableStage и будут выполнены на том CompletableStage , который первее выполнится. И закончить этот обзор хочется ещё одной интересной возможностью CompletableFuture — обработкой ошибок.

 CompletableFuture.completedFuture(2L) .thenApply((a) -> < throw new IllegalStateException("error"); >).thenApply((a) -> 3L) //.exceptionally(ex -> 0L) .thenAccept(val -> System.out.println(val)); 

Заключение

Источник

Читайте также:  Теги html тег div
Оцените статью